diff --git a/counter/tests/test_counter.py b/counter/tests/test_counter.py index 02575884..5b96a471 100644 --- a/counter/tests/test_counter.py +++ b/counter/tests/test_counter.py @@ -46,6 +46,15 @@ from counter.models import ( ) +def set_age(user: User, age: int): + user.date_of_birth = localdate().replace(year=localdate().year - age) + user.save() + + +def force_refill_user(user: User, amount: Decimal | int): + baker.make(Refilling, amount=amount, customer=user.customer, is_validated=False) + + class TestFullClickBase(TestCase): @classmethod def setUpTestData(cls): @@ -226,11 +235,11 @@ class TestCounterClick(TestFullClickBase): cls.banned_counter_customer = subscriber_user.make() cls.banned_alcohol_customer = subscriber_user.make() - cls.set_age(cls.customer, 20) - cls.set_age(cls.barmen, 20) - cls.set_age(cls.club_admin, 20) - cls.set_age(cls.banned_alcohol_customer, 20) - cls.set_age(cls.underage_customer, 17) + set_age(cls.customer, 20) + set_age(cls.barmen, 20) + set_age(cls.club_admin, 20) + set_age(cls.banned_alcohol_customer, 20) + set_age(cls.underage_customer, 17) cls.banned_alcohol_customer.ban_groups.add( BanGroup.objects.get(pk=settings.SITH_GROUP_BANNED_ALCOHOL_ID) @@ -278,11 +287,6 @@ class TestCounterClick(TestFullClickBase): {"username": used_barman.username, "password": "plop"}, ) - @classmethod - def set_age(cls, user: User, age: int): - user.date_of_birth = localdate().replace(year=localdate().year - age) - user.save() - def submit_basket( self, user: User, @@ -306,9 +310,6 @@ class TestCounterClick(TestFullClickBase): data, ) - def refill_user(self, user: User, amount: Decimal | int): - baker.make(Refilling, amount=amount, customer=user.customer, is_validated=False) - def test_click_eboutic_failure(self): eboutic = baker.make(Counter, type="EBOUTIC") self.client.force_login(self.club_admin) @@ -318,7 +319,7 @@ class TestCounterClick(TestFullClickBase): assert res.status_code == 404 def test_click_office_success(self): - self.refill_user(self.customer, 10) + force_refill_user(self.customer, 10) self.client.force_login(self.club_admin) res = self.submit_basket( self.customer, [BasketItem(self.stamps.id, 5)], counter=self.club_counter @@ -327,7 +328,7 @@ class TestCounterClick(TestFullClickBase): assert self.updated_amount(self.customer) == Decimal("2.5") # Test no special price on office counter - self.refill_user(self.club_admin, 10) + force_refill_user(self.club_admin, 10) res = self.submit_basket( self.club_admin, [BasketItem(self.stamps.id, 1)], counter=self.club_counter ) @@ -336,7 +337,7 @@ class TestCounterClick(TestFullClickBase): assert self.updated_amount(self.club_admin) == Decimal("8.5") def test_click_bar_success(self): - self.refill_user(self.customer, 10) + force_refill_user(self.customer, 10) self.login_in_bar(self.barmen) res = self.submit_basket( self.customer, [BasketItem(self.beer.id, 2), BasketItem(self.snack.id, 1)] @@ -347,7 +348,7 @@ class TestCounterClick(TestFullClickBase): # Test barmen special price - self.refill_user(self.barmen, 10) + force_refill_user(self.barmen, 10) assert ( self.submit_basket(self.barmen, [BasketItem(self.beer.id, 1)]) @@ -356,7 +357,7 @@ class TestCounterClick(TestFullClickBase): assert self.updated_amount(self.barmen) == Decimal("9") def test_click_tray_price(self): - self.refill_user(self.customer, 20) + force_refill_user(self.customer, 20) self.login_in_bar(self.barmen) # Not applying tray price @@ -373,7 +374,7 @@ class TestCounterClick(TestFullClickBase): self.login_in_bar() for user in [self.underage_customer, self.banned_alcohol_customer]: - self.refill_user(user, 10) + force_refill_user(user, 10) # Buy product without age limit res = self.submit_basket(user, [BasketItem(self.snack.id, 2)]) @@ -394,7 +395,7 @@ class TestCounterClick(TestFullClickBase): self.banned_counter_customer, self.customer_old_can_not_buy, ]: - self.refill_user(user, 10) + force_refill_user(user, 10) resp = self.submit_basket(user, [BasketItem(self.snack.id, 2)]) assert resp.status_code == 302 assert resp.url == resolve_url(self.counter) @@ -410,7 +411,7 @@ class TestCounterClick(TestFullClickBase): def test_click_allowed_old_subscriber(self): self.login_in_bar() - self.refill_user(self.customer_old_can_buy, 10) + force_refill_user(self.customer_old_can_buy, 10) res = self.submit_basket( self.customer_old_can_buy, [BasketItem(self.snack.id, 2)] ) @@ -420,7 +421,7 @@ class TestCounterClick(TestFullClickBase): def test_click_wrong_counter(self): self.login_in_bar() - self.refill_user(self.customer, 10) + force_refill_user(self.customer, 10) res = self.submit_basket( self.customer, [BasketItem(self.snack.id, 2)], counter=self.other_counter ) @@ -444,7 +445,7 @@ class TestCounterClick(TestFullClickBase): assert self.updated_amount(self.customer) == Decimal("10") def test_click_not_connected(self): - self.refill_user(self.customer, 10) + force_refill_user(self.customer, 10) res = self.submit_basket(self.customer, [BasketItem(self.snack.id, 2)]) assertRedirects(res, self.counter.get_absolute_url()) @@ -456,15 +457,29 @@ class TestCounterClick(TestFullClickBase): assert self.updated_amount(self.customer) == Decimal("10") def test_click_product_not_in_counter(self): - self.refill_user(self.customer, 10) + force_refill_user(self.customer, 10) self.login_in_bar() res = self.submit_basket(self.customer, [BasketItem(self.stamps.id, 2)]) assert res.status_code == 200 assert self.updated_amount(self.customer) == Decimal("10") + def test_basket_empty(self): + force_refill_user(self.customer, 10) + + for basket in [ + [], + [BasketItem(None, None)], + [BasketItem(None, None), BasketItem(None, None)], + ]: + assertRedirects( + self.submit_basket(self.customer, basket), + self.counter.get_absolute_url(), + ) + assert self.updated_amount(self.customer) == Decimal("10") + def test_click_product_invalid(self): - self.refill_user(self.customer, 10) + force_refill_user(self.customer, 10) self.login_in_bar() for item in [ @@ -472,14 +487,12 @@ class TestCounterClick(TestFullClickBase): BasketItem(self.beer.id, -1), BasketItem(None, 1), BasketItem(self.beer.id, None), - BasketItem(None, None), ]: assert self.submit_basket(self.customer, [item]).status_code == 200 - assert self.updated_amount(self.customer) == Decimal("10") def test_click_not_enough_money(self): - self.refill_user(self.customer, 10) + force_refill_user(self.customer, 10) self.login_in_bar() res = self.submit_basket( self.customer, @@ -509,7 +522,7 @@ class TestCounterClick(TestFullClickBase): assert self.updated_amount(self.customer) == 0 def test_recordings(self): - self.refill_user(self.customer, self.cons.selling_price * 3) + force_refill_user(self.customer, self.cons.selling_price * 3) self.login_in_bar(self.barmen) res = self.submit_basket(self.customer, [BasketItem(self.cons.id, 3)]) assert res.status_code == 302 diff --git a/eboutic/tests/test_basket.py b/eboutic/tests/test_basket.py new file mode 100644 index 00000000..856a0784 --- /dev/null +++ b/eboutic/tests/test_basket.py @@ -0,0 +1,169 @@ +from django.http import HttpResponse +from django.test import TestCase +from django.test.client import Client +from django.urls import reverse +from django.utils.timezone import localdate +from model_bakery import baker +from pytest_django.asserts import assertRedirects + +from core.baker_recipes import subscriber_user +from core.models import Group, User +from counter.baker_recipes import product_recipe +from counter.models import Counter, ProductType +from counter.tests.test_counter import BasketItem +from eboutic.models import Basket + + +class TestEboutic(TestCase): + @classmethod + def setUpTestData(cls): + cls.group_cotiz = baker.make(Group) + cls.group_public = baker.make(Group) + + cls.new_customer = baker.make(User) + cls.new_customer_adult = baker.make(User) + cls.subscriber = subscriber_user.make() + + cls.set_age(cls.new_customer, 5) + cls.set_age(cls.new_customer_adult, 20) + cls.set_age(cls.subscriber, 20) + + product_type = baker.make(ProductType) + + cls.snack = product_recipe.make( + selling_price=1.5, special_selling_price=1, product_type=product_type + ) + cls.beer = product_recipe.make( + limit_age=18, + selling_price=2.5, + special_selling_price=1, + product_type=product_type, + ) + cls.not_in_counter = product_recipe.make( + selling_price=3.5, product_type=product_type + ) + cls.cotiz = product_recipe.make(selling_price=10, product_type=product_type) + + cls.group_public.products.add(cls.snack, cls.beer, cls.not_in_counter) + cls.group_cotiz.products.add(cls.cotiz) + + cls.subscriber.groups.add(cls.group_cotiz, cls.group_public) + cls.new_customer.groups.add(cls.group_public) + cls.new_customer_adult.groups.add(cls.group_public) + + cls.eboutic = Counter.objects.get(name="Eboutic") + cls.eboutic.products.add(cls.cotiz, cls.beer, cls.snack) + + @classmethod + def set_age(cls, user: User, age: int): + user.date_of_birth = localdate().replace(year=localdate().year - age) + user.save() + + def submit_basket( + self, basket: list[BasketItem], client: Client | None = None + ) -> HttpResponse: + used_client: Client = client if client is not None else self.client + data = { + "form-TOTAL_FORMS": str(len(basket)), + "form-INITIAL_FORMS": "0", + } + for index, item in enumerate(basket): + data.update(item.to_form(index)) + return used_client.post(reverse("eboutic:main"), data) + + def test_submit_empty_basket(self): + self.client.force_login(self.subscriber) + for basket in [ + [], + [BasketItem(None, None)], + [BasketItem(None, None), BasketItem(None, None)], + ]: + response = self.submit_basket(basket) + assert response.status_code == 200 + assert "Votre panier est vide" in response.text + + def test_submit_invalid_basket(self): + self.client.force_login(self.subscriber) + for item in [ + BasketItem(-1, 2), + BasketItem(self.snack.id, -1), + BasketItem(None, 1), + BasketItem(self.snack.id, None), + ]: + assert self.submit_basket([item]).status_code == 200 + + def test_anonymous(self): + assertRedirects( + self.client.get(reverse("eboutic:main")), + reverse("core:login", query={"next": reverse("eboutic:main")}), + ) + assertRedirects( + self.submit_basket([]), + reverse("core:login", query={"next": reverse("eboutic:main")}), + ) + assertRedirects( + self.submit_basket([BasketItem(self.snack.id, 1)]), + reverse("core:login", query={"next": reverse("eboutic:main")}), + ) + + def test_add_forbidden_product(self): + self.client.force_login(self.new_customer) + assert self.submit_basket([BasketItem(self.beer.id, 1)]).status_code == 200 + assert Basket.objects.first() is None + + assert self.submit_basket([BasketItem(self.cotiz.id, 1)]).status_code == 200 + assert Basket.objects.first() is None + + assert ( + self.submit_basket([BasketItem(self.not_in_counter.id, 1)]).status_code + == 200 + ) + assert Basket.objects.first() is None + + self.client.force_login(self.new_customer) + assert self.submit_basket([BasketItem(self.cotiz.id, 1)]).status_code == 200 + assert Basket.objects.first() is None + + assert ( + self.submit_basket([BasketItem(self.not_in_counter.id, 1)]).status_code + == 200 + ) + assert Basket.objects.first() is None + + def test_create_basket(self): + self.client.force_login(self.new_customer) + assertRedirects( + self.submit_basket([BasketItem(self.snack.id, 2)]), + reverse("eboutic:checkout", kwargs={"basket_id": 1}), + ) + assert Basket.objects.get(id=1).total == self.snack.selling_price * 2 + + self.client.force_login(self.new_customer_adult) + assertRedirects( + self.submit_basket( + [BasketItem(self.snack.id, 2), BasketItem(self.beer.id, 1)] + ), + reverse("eboutic:checkout", kwargs={"basket_id": 2}), + ) + assert ( + Basket.objects.get(id=2).total + == self.snack.selling_price * 2 + self.beer.selling_price + ) + + self.client.force_login(self.subscriber) + assertRedirects( + self.submit_basket( + [ + BasketItem(self.snack.id, 2), + BasketItem(self.beer.id, 1), + BasketItem(self.cotiz.id, 1), + ] + ), + reverse("eboutic:checkout", kwargs={"basket_id": 3}), + ) + assert ( + Basket.objects.get(id=3).total + == self.snack.selling_price * 2 + + self.beer.selling_price + + self.cotiz.selling_price + ) diff --git a/eboutic/tests/tests.py b/eboutic/tests/tests.py index 33555bdf..c61dd374 100644 --- a/eboutic/tests/tests.py +++ b/eboutic/tests/tests.py @@ -30,7 +30,6 @@ from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15 from cryptography.hazmat.primitives.hashes import SHA1 from cryptography.hazmat.primitives.serialization import load_pem_private_key from django.conf import settings -from django.db.models import Max from django.test import TestCase from django.urls import reverse @@ -113,59 +112,6 @@ class TestEboutic(TestCase): expected = 'basket_items=""; expires=Thu, 01 Jan 1970 00:00:00 GMT; Max-Age=0; Path=/eboutic' assert expected == self.client.cookies["basket_items"].OutputString() - def test_submit_basket(self): - self.client.force_login(self.subscriber) - self.client.cookies["basket_items"] = """[ - {"id": 2, "name": "Cotis 2 semestres", "quantity": 1, "unit_price": 28}, - {"id": 4, "name": "Barbar", "quantity": 3, "unit_price": 1.7} - ]""" - response = self.client.get(reverse("eboutic:command")) - assert response.status_code == 200 - self.assertInHTML( - "Cotis 2 semestres128.00 €", - response.text, - ) - self.assertInHTML( - "Barbar31.70 €", - response.text, - ) - assert "basket_id" in self.client.session - basket = Basket.objects.get(id=self.client.session["basket_id"]) - assert basket.items.count() == 2 - barbar = basket.items.filter(product_name="Barbar").first() - assert barbar is not None - assert barbar.quantity == 3 - cotis = basket.items.filter(product_name="Cotis 2 semestres").first() - assert cotis is not None - assert cotis.quantity == 1 - assert basket.total == 3 * 1.7 + 28 - - def test_submit_empty_basket(self): - self.client.force_login(self.subscriber) - self.client.cookies["basket_items"] = "[]" - response = self.client.get(reverse("eboutic:command")) - self.assertRedirects(response, "/eboutic/") - - def test_submit_invalid_basket(self): - self.client.force_login(self.subscriber) - max_id = Product.objects.aggregate(res=Max("id"))["res"] - self.client.cookies["basket_items"] = f"""[ - {{"id": {max_id + 1}, "name": "", "quantity": 1, "unit_price": 28}} - ]""" - response = self.client.get(reverse("eboutic:command")) - cookie = self.client.cookies["basket_items"].OutputString() - assert 'basket_items="[]"' in cookie - assert "Path=/eboutic" in cookie - self.assertRedirects(response, "/eboutic/") - - def test_submit_basket_illegal_quantity(self): - self.client.force_login(self.subscriber) - self.client.cookies["basket_items"] = """[ - {"id": 4, "name": "Barbar", "quantity": -1, "unit_price": 1.7} - ]""" - response = self.client.get(reverse("eboutic:command")) - self.assertRedirects(response, "/eboutic/") - def test_buy_subscribe_product_with_credit_card(self): self.client.force_login(self.old_subscriber) response = self.client.get(