def test_category_deletion(admin_user): admin = get_person_contact(admin_user) category = get_default_category() category.children.create(identifier="foo") shop_product = get_default_shop_product() shop_product.categories.add(category) shop_product.primary_category = category shop_product.save() configuration.set(None, get_all_seeing_key(admin), True) assert category.status == CategoryStatus.VISIBLE assert category.children.count() == 1 with pytest.raises(NotImplementedError): category.delete() category.soft_delete() shop_product.refresh_from_db() shop_product.product.refresh_from_db() assert shop_product.categories.count() == 0 assert shop_product.primary_category is None assert category.status == CategoryStatus.DELETED assert category.children.count() == 0 # the child category still exists assert Category.objects.all_visible(customer=admin).count() == 1 assert Category.objects.all_except_deleted().count() == 1 configuration.set(None, get_all_seeing_key(admin), False)
def test_product_caching_object(): shop_product = get_default_shop_product() product = shop_product.product another_product = create_product("PCOTestProduct") pco = ProductCachingObject() pco.product = product assert pco.product is product assert pco.product_id == product.pk assert ProductCachingObject( ).product != pco.product # Assert PCOs are separate assert pco._product_cache == pco.product # This private property is courtesy of ModelCachingDescriptor pco = ProductCachingObject() pco.product_id = product.pk assert pco.product == product assert pco.product_id == product.pk # Not creating a new PCO here pco.product = another_product assert pco.product == another_product assert pco.product_id == another_product.pk # Nor here pco.product_id = product.pk assert pco.product == product assert pco.product_id == product.pk
def test_product_unsupplied(admin_user): shop_product = get_default_shop_product() fake_supplier = Supplier.objects.create(identifier="fake") admin_contact = get_person_contact(admin_user) with modify(shop_product, visibility_limit=ProductVisibility.VISIBLE_TO_ALL, orderable=True): assert any(ve.code == "invalid_supplier" for ve in shop_product.get_orderability_errors(supplier=fake_supplier, customer=admin_contact, quantity=1))
def test_default_supplier(): supplier = get_default_supplier() shop_product = get_default_shop_product() product = shop_product.product assert supplier.get_stock_statuses([product.id ])[product.id].logical_count == 0 assert not list( supplier.get_orderability_errors(shop_product, 1, customer=None))
def test_product_minimum_order_quantity(admin_user): shop_product = get_default_shop_product() supplier = get_default_supplier() admin_contact = get_person_contact(admin_user) with modify(shop_product, visibility_limit=ProductVisibility.VISIBLE_TO_ALL, orderable=True, minimum_purchase_quantity=10): assert any(ve.code == "purchase_quantity_not_met" for ve in shop_product.get_orderability_errors(supplier=supplier, customer=admin_contact, quantity=1)) assert not any(ve.code == "purchase_quantity_not_met" for ve in shop_product.get_orderability_errors(supplier=supplier, customer=admin_contact, quantity=15))
def test_product_order_multiple(admin_user): shop_product = get_default_shop_product() supplier = get_default_supplier() admin_contact = get_person_contact(admin_user) with modify(shop_product, visibility_limit=ProductVisibility.VISIBLE_TO_ALL, orderable=True, purchase_multiple=7): assert any(ve.code == "invalid_purchase_multiple" for ve in shop_product.get_orderability_errors(supplier=supplier, customer=admin_contact, quantity=4)) assert any(ve.code == "invalid_purchase_multiple" for ve in shop_product.get_orderability_errors(supplier=supplier, customer=admin_contact, quantity=25)) assert not any(ve.code == "invalid_purchase_multiple" for ve in shop_product.get_orderability_errors(supplier=supplier, customer=admin_contact, quantity=49))
def test_product_categories(settings): with override_settings(WSHOP_AUTO_SHOP_PRODUCT_CATEGORIES=True): shop_product = get_default_shop_product() shop_product.categories.clear() shop_product.primary_category = None shop_product.save() assert not shop_product.primary_category assert not shop_product.categories.count() category_one = CategoryFactory() category_two = CategoryFactory() shop_product.categories = Category.objects.all() assert shop_product.primary_category # this was automatically populated assert shop_product.primary_category.pk == category_one.pk # it's the first one also shop_product.categories.clear() shop_product.primary_category = category_one shop_product.save() assert shop_product.primary_category == category_one assert category_one in shop_product.categories.all() # test removing shop_product.categories.remove(category_one) shop_product.refresh_from_db() assert not shop_product.categories.exists() shop_product.categories.add(category_one) category_one.soft_delete() assert not shop_product.categories.exists() with override_settings(WSHOP_AUTO_SHOP_PRODUCT_CATEGORIES=False): shop_product.categories.clear() shop_product.primary_category = None shop_product.save() assert not shop_product.primary_category assert not shop_product.categories.count() category_one = CategoryFactory() category_two = CategoryFactory() shop_product.categories = Category.objects.all() assert not shop_product.primary_category # this was NOT automatically populated shop_product.categories.clear() shop_product.primary_category = category_one shop_product.save() assert shop_product.primary_category == category_one assert category_one not in shop_product.categories.all()
def test_product_orderability(): anon_contact = AnonymousContact() shop_product = get_default_shop_product() supplier = get_default_supplier() with modify(shop_product, visibility_limit=ProductVisibility.VISIBLE_TO_ALL, orderable=True): shop_product.raise_if_not_orderable(supplier=supplier, customer=anon_contact, quantity=1) assert shop_product.is_orderable(supplier=supplier, customer=anon_contact, quantity=1) with modify(shop_product, visibility_limit=ProductVisibility.VISIBLE_TO_LOGGED_IN, orderable=True): with pytest.raises(ProductNotOrderableProblem): shop_product.raise_if_not_orderable(supplier=supplier, customer=anon_contact, quantity=1) assert not shop_product.is_orderable(supplier=supplier, customer=anon_contact, quantity=1)
def test_get_suppliable_products(): customer = create_random_person() shop_product = get_default_shop_product() shop = get_default_shop() supplier = get_default_supplier() # Check for default orderable shop product with unstocked behavior assert len(list(supplier.get_suppliable_products(shop, customer=customer))) == 1 product = shop_product.product product.stock_behavior = StockBehavior.STOCKED product.save() # Make sure supplier now omits unorderable product assert not list(supplier.get_suppliable_products(shop, customer=customer)) assert len( list( supplier.get_orderability_errors(shop_product, quantity=1, customer=customer))) == 1 shop_product.backorder_maximum = 10 shop_product.save() assert len(list(supplier.get_suppliable_products(shop, customer=customer))) == 1 assert len( list( supplier.get_orderability_errors(shop_product, quantity=10, customer=customer))) == 0 assert len( list( supplier.get_orderability_errors(shop_product, quantity=11, customer=customer))) == 1 shop_product.backorder_maximum = None shop_product.save() assert len(list(supplier.get_suppliable_products(shop, customer=customer))) == 1 assert len( list( supplier.get_orderability_errors(shop_product, quantity=1000, customer=customer))) == 0
def test_product_query_with_group_visibility(regular_user): default_group = get_default_customer_group() shop_product = get_default_shop_product() shop_product.visibility_limit = 3 shop_product.save() shop = shop_product.shop product = shop_product.product shop_product.visibility_groups.add(default_group) regular_contact = get_person_contact(regular_user) assert not Product.objects.listed( shop=shop, customer=regular_contact).filter(pk=product.pk).exists() regular_contact.groups.add(default_group) assert Product.objects.listed( shop=shop, customer=regular_contact).filter(pk=product.pk).count() == 1 shop_product.visibility_groups.add(regular_contact.get_default_group()) # Multiple visibility groups for shop product shouldn't cause duplicate matches assert Product.objects.listed( shop=shop, customer=regular_contact).filter(pk=product.pk).count() == 1
def test_product_visibility(rf, admin_user, regular_user): anon_contact = get_person_contact(AnonymousUser()) shop_product = get_default_shop_product() admin_contact = get_person_contact(admin_user) regular_contact = get_person_contact(regular_user) configuration.set(None, get_all_seeing_key(admin_contact), True) with modify(shop_product.product, deleted=True): # NB: assigning to `product` here works because `get_shop_instance` populates `_product_cache` assert error_exists(shop_product.get_visibility_errors(customer=anon_contact), "product_deleted") assert error_exists(shop_product.get_visibility_errors(customer=admin_contact), "product_deleted") with pytest.raises(ProductNotVisibleProblem): shop_product.raise_if_not_visible(anon_contact) assert not shop_product.is_list_visible() with modify(shop_product, visibility_limit=ProductVisibility.VISIBLE_TO_ALL, visibility=ShopProductVisibility.NOT_VISIBLE): assert error_exists(shop_product.get_visibility_errors(customer=anon_contact), "product_not_visible") assert error_does_not_exist(shop_product.get_visibility_errors(customer=admin_contact), "product_not_visible") assert not shop_product.is_list_visible() with modify(shop_product, visibility_limit=ProductVisibility.VISIBLE_TO_LOGGED_IN, visibility=ShopProductVisibility.ALWAYS_VISIBLE): assert error_exists(shop_product.get_visibility_errors(customer=anon_contact), "product_not_visible_to_anonymous") assert error_does_not_exist(shop_product.get_visibility_errors(customer=admin_contact), "product_not_visible_to_anonymous") customer_group = get_default_customer_group() grouped_user = get_user_model().objects.create_user(username=printable_gibberish(20)) grouped_contact = get_person_contact(grouped_user) with modify(shop_product, visibility_limit=ProductVisibility.VISIBLE_TO_GROUPS, visibility=ShopProductVisibility.ALWAYS_VISIBLE): shop_product.visibility_groups.add(customer_group) customer_group.members.add(grouped_contact) customer_group.members.remove(get_person_contact(regular_user)) assert error_does_not_exist(shop_product.get_visibility_errors(customer=grouped_contact), "product_not_visible_to_group") assert error_does_not_exist(shop_product.get_visibility_errors(customer=admin_contact), "product_not_visible_to_group") assert error_exists(shop_product.get_visibility_errors(customer=regular_contact), "product_not_visible_to_group") configuration.set(None, get_all_seeing_key(admin_contact), False)
def test_adjust_stock(admin_user): get_default_shop() sp = get_default_shop_product() sp.stock_behavior = StockBehavior.STOCKED sp.save() client = _get_client(admin_user) supplier1 = get_simple_supplier() supplier2 = get_default_supplier() # invalid type response = client.post("/api/wshop/supplier/%s/adjust_stock/" % supplier1.pk, format="json", data={ "product": sp.product.pk, "delta": 100, "type": 200 }) assert response.status_code == status.HTTP_400_BAD_REQUEST data = json.loads(response.content.decode("utf-8")) assert "type" in data # invalid supplier response = client.post("/api/wshop/supplier/%s/adjust_stock/" % 100, format="json", data={ "product": sp.product.pk, "delta": 100, "type": StockAdjustmentType.INVENTORY.value }) assert response.status_code == status.HTTP_404_NOT_FOUND # invalid product response = client.post("/api/wshop/supplier/%s/adjust_stock/" % supplier1.pk, format="json", data={ "product": 100, "delta": 100, "type": StockAdjustmentType.INVENTORY.value }) assert response.status_code == status.HTTP_400_BAD_REQUEST data = json.loads(response.content.decode("utf-8")) assert "product" in data # invalid delta response = client.post("/api/wshop/supplier/%s/adjust_stock/" % supplier1.pk, format="json", data={ "product": sp.product.pk, "delta": "not-a-number", "type": StockAdjustmentType.INVENTORY.value }) assert response.status_code == status.HTTP_400_BAD_REQUEST data = json.loads(response.content.decode("utf-8")) assert "delta" in data # adjust stock not implemented response = client.post("/api/wshop/supplier/%s/adjust_stock/" % supplier2.pk, format="json", data={ "product": sp.product.pk, "delta": 100, "type": StockAdjustmentType.INVENTORY.value }) assert response.status_code == status.HTTP_400_BAD_REQUEST # add 100 to inventory response = client.post("/api/wshop/supplier/%s/adjust_stock/" % supplier1.pk, format="json", data={ "product": sp.product.pk, "delta": 100, "type": StockAdjustmentType.RESTOCK.value }) assert response.status_code == status.HTTP_200_OK stock = supplier1.get_stock_status(sp.product.pk) assert stock.logical_count == 100 assert stock.physical_count == 100 # remove the stocks adjustments and calculate the stock again StockAdjustment.objects.all().delete() # update the stock, response = client.post("/api/wshop/supplier/%s/update_stocks/" % supplier1.pk, format="json", data={ "products": [sp.product.pk] }) assert response.status_code == status.HTTP_200_OK # everything should be zero stock = supplier1.get_stock_status(sp.product.pk) assert stock.logical_count == 0 assert stock.physical_count == 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