# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later from api.tests import TestAPI from member.models import Club, Membership from django.contrib.auth.models import User from django.contrib.contenttypes.models import ContentType from django.test import TestCase from django.urls import reverse from django.utils import timezone from permission.models import Role from ..api.views import AliasViewSet, ConsumerViewSet, NotePolymorphicViewSet, TemplateCategoryViewSet,\ TransactionTemplateViewSet, TransactionViewSet from ..models import NoteUser, Transaction, TemplateCategory, TransactionTemplate, RecurrentTransaction, \ MembershipTransaction, SpecialTransaction, NoteSpecial, Alias, Note class TestTransactions(TestCase): fixtures = ('initial', ) def setUp(self) -> None: self.user = User.objects.create_superuser( username="toto", password="totototo", email="toto@example.com", ) sess = self.client.session sess["permission_mask"] = 42 sess.save() self.client.force_login(self.user) membership = Membership.objects.create(club=Club.objects.get(name="BDE"), user=self.user) membership.roles.add(Role.objects.get(name="Respo info")) membership.save() Membership.objects.create(club=Club.objects.get(name="Kfet"), user=self.user) self.user.note.refresh_from_db() self.second_user = User.objects.create( username="toto2", ) # Non superusers have no note until the registration get validated NoteUser.objects.create(user=self.second_user) self.club = Club.objects.create( name="clubtoto", ) self.transaction = Transaction.objects.create( source=self.second_user.note, destination=self.user.note, amount=4200, reason="Test transaction", ) self.user.note.refresh_from_db() self.second_user.note.refresh_from_db() self.category = TemplateCategory.objects.create(name="Test") self.template = TransactionTemplate.objects.create( name="Test", destination=self.club.note, category=self.category, amount=100, description="Test template", ) def test_admin_pages(self): """ Load some admin pages to check that they render successfully. """ response = self.client.get(reverse("admin:index") + "note/note/") self.assertEqual(response.status_code, 200) response = self.client.get(reverse("admin:index") + "note/transaction/") self.assertEqual(response.status_code, 200) response = self.client.get(reverse("admin:index") + "note/transaction/" + str(self.transaction.pk) + "/change/") self.assertEqual(response.status_code, 200) response = self.client.get(reverse("admin:index") + "note/transaction/add/?ct_id=" + str(ContentType.objects.get_for_model(Transaction).id)) self.assertEqual(response.status_code, 200) response = self.client.get(reverse("admin:index") + "note/transaction/add/?ct_id=" + str(ContentType.objects.get_for_model(RecurrentTransaction).id)) self.assertEqual(response.status_code, 200) response = self.client.get(reverse("admin:index") + "note/transaction/add/?ct_id=" + str(ContentType.objects.get_for_model(MembershipTransaction).id)) self.assertEqual(response.status_code, 200) response = self.client.get(reverse("admin:index") + "note/transaction/add/?ct_id=" + str(ContentType.objects.get_for_model(SpecialTransaction).id)) self.assertEqual(response.status_code, 200) response = self.client.get(reverse("admin:index") + "note/transactiontemplate/") self.assertEqual(response.status_code, 200) response = self.client.get(reverse("admin:index") + "note/templatecategory/") self.assertEqual(response.status_code, 200) def test_render_transfer_page(self): response = self.client.get(reverse("note:transfer")) self.assertEqual(response.status_code, 200) def test_transfer_api(self): old_user_balance = self.user.note.balance old_second_user_balance = self.second_user.note.balance quantity = 3 amount = 314 total = quantity * amount response = self.client.post("/api/note/transaction/transaction/", data=dict( quantity=quantity, amount=amount, reason="Transaction through API", valid=True, polymorphic_ctype=ContentType.objects.get_for_model(Transaction).id, resourcetype="Transaction", source=self.user.note.id, source_alias=self.user.username, destination=self.second_user.note.id, destination_alias=self.second_user.username, )) self.assertEqual(response.status_code, 201) # 201 = Created self.assertTrue(Transaction.objects.filter(reason="Transaction through API").exists()) self.user.note.refresh_from_db() self.second_user.note.refresh_from_db() self.assertTrue(self.user.note.balance == old_user_balance - total) self.assertTrue(self.second_user.note.balance == old_second_user_balance + total) self.test_render_transfer_page() def test_credit_api(self): old_user_balance = self.user.note.balance amount = 4242 special_type = NoteSpecial.objects.first() response = self.client.post("/api/note/transaction/transaction/", data=dict( quantity=1, amount=amount, reason="Credit through API", valid=True, polymorphic_ctype=ContentType.objects.get_for_model(SpecialTransaction).id, resourcetype="SpecialTransaction", source=special_type.id, source_alias=str(special_type), destination=self.user.note.id, destination_alias=self.user.username, last_name="TOTO", first_name="Toto", )) self.assertEqual(response.status_code, 201) # 201 = Created self.assertTrue(Transaction.objects.filter(reason="Credit through API").exists()) self.user.note.refresh_from_db() self.assertTrue(self.user.note.balance == old_user_balance + amount) self.test_render_transfer_page() def test_debit_api(self): old_user_balance = self.user.note.balance amount = 4242 special_type = NoteSpecial.objects.first() response = self.client.post("/api/note/transaction/transaction/", data=dict( quantity=1, amount=amount, reason="Debit through API", valid=True, polymorphic_ctype=ContentType.objects.get_for_model(SpecialTransaction).id, resourcetype="SpecialTransaction", source=self.user.note.id, source_alias=self.user.username, destination=special_type.id, destination_alias=str(special_type), last_name="TOTO", first_name="Toto", )) self.assertEqual(response.status_code, 201) # 201 = Created self.assertTrue(Transaction.objects.filter(reason="Debit through API").exists()) self.user.note.refresh_from_db() self.assertTrue(self.user.note.balance == old_user_balance - amount) self.test_render_transfer_page() def test_render_consos_page(self): response = self.client.get(reverse("note:consos")) self.assertEqual(response.status_code, 200) def test_consumption_api(self): old_user_balance = self.user.note.balance old_club_balance = self.club.note.balance quantity = 2 template = self.template total = quantity * template.amount response = self.client.post("/api/note/transaction/transaction/", data=dict( quantity=quantity, amount=template.amount, reason="Consumption through API (" + template.name + ")", valid=True, polymorphic_ctype=ContentType.objects.get_for_model(RecurrentTransaction).id, resourcetype="RecurrentTransaction", source=self.user.note.id, source_alias=self.user.username, destination=self.club.note.id, destination_alias=self.second_user.username, template=template.id, )) self.assertEqual(response.status_code, 201) # 201 = Created self.assertTrue(Transaction.objects.filter(destination=self.club.note).exists()) self.user.note.refresh_from_db() self.club.note.refresh_from_db() self.assertTrue(self.user.note.balance == old_user_balance - total) self.assertTrue(self.club.note.balance == old_club_balance + total) self.test_render_consos_page() def test_invalidate_transaction(self): old_second_user_balance = self.second_user.note.balance old_user_balance = self.user.note.balance total = self.transaction.total response = self.client.patch("/api/note/transaction/transaction/" + str(self.transaction.pk) + "/", data=dict( valid=False, resourcetype="Transaction", invalidity_reason="Test invalidate", ), content_type="application/json") self.assertEqual(response.status_code, 200) self.assertTrue(Transaction.objects.filter(valid=False, invalidity_reason="Test invalidate").exists()) self.second_user.note.refresh_from_db() self.user.note.refresh_from_db() self.assertTrue(self.second_user.note.balance == old_second_user_balance + total) self.assertTrue(self.user.note.balance == old_user_balance - total) self.test_render_transfer_page() self.test_render_consos_page() # Now we check if we can revalidate old_second_user_balance = self.second_user.note.balance old_user_balance = self.user.note.balance total = self.transaction.total response = self.client.patch("/api/note/transaction/transaction/" + str(self.transaction.pk) + "/", data=dict( valid=True, resourcetype="Transaction", ), content_type="application/json") self.assertEqual(response.status_code, 200) self.assertTrue(Transaction.objects.filter(valid=True, pk=self.transaction.pk).exists()) self.second_user.note.refresh_from_db() self.user.note.refresh_from_db() self.assertTrue(self.second_user.note.balance == old_second_user_balance - total) self.assertTrue(self.user.note.balance == old_user_balance + total) self.test_render_transfer_page() self.test_render_consos_page() def test_render_template_list(self): response = self.client.get(reverse("note:template_list") + "?search=test") self.assertEqual(response.status_code, 200) def test_render_template_create(self): response = self.client.get(reverse("note:template_create")) self.assertEqual(response.status_code, 200) response = self.client.post(reverse("note:template_create"), data=dict( name="Test create button", destination=self.club.note.pk, category=self.category.pk, amount=4200, description="We have created a button", highlighted=True, display=True, )) self.assertRedirects(response, reverse("note:template_list"), 302, 200) self.assertTrue(TransactionTemplate.objects.filter(name="Test create button").exists()) def test_render_template_update(self): response = self.client.get(self.template.get_absolute_url()) self.assertEqual(response.status_code, 200) response = self.client.post(self.template.get_absolute_url(), data=dict( name="Test update button", destination=self.club.note.pk, category=self.category.pk, amount=4200, description="We have updated a button", highlighted=True, display=True, )) self.assertRedirects(response, reverse("note:template_list"), 302, 200) self.assertTrue(TransactionTemplate.objects.filter(name="Test update button", pk=self.template.pk).exists()) # Check that the price history renders properly response = self.client.post(self.template.get_absolute_url(), data=dict( name="Test price history", destination=self.club.note.pk, category=self.category.pk, amount=4200, description="We have updated a button", highlighted=True, display=True, )) self.assertRedirects(response, reverse("note:template_list"), 302, 200) self.assertTrue(TransactionTemplate.objects.filter(name="Test price history", pk=self.template.pk).exists()) response = self.client.get(reverse("note:template_update", args=(self.template.pk,))) self.assertEqual(response.status_code, 200) def test_render_search_transactions(self): response = self.client.get(reverse("note:transactions", args=(self.user.note.pk,)), data=dict( source=self.second_user.note.alias.first().id, destination=self.user.note.alias.first().id, type=[ContentType.objects.get_for_model(Transaction).id], reason="test", valid=True, amount_gte=0, amount_lte=42424242, created_after="2000-01-01 00:00", created_before="2042-12-31 21:42", )) self.assertEqual(response.status_code, 200) def test_delete_transaction(self): # Transactions can't be deleted with a normal usage, but it is possible through the admin interface. old_second_user_balance = self.second_user.note.balance old_user_balance = self.user.note.balance total = self.transaction.total self.transaction.delete() self.second_user.note.refresh_from_db() self.user.note.refresh_from_db() self.assertTrue(self.second_user.note.balance == old_second_user_balance + total) self.assertTrue(self.user.note.balance == old_user_balance - total) def test_calculate_last_negative_duration(self): self.assertIsNone(self.user.note.last_negative_duration) self.assertIsNotNone(self.second_user.note.last_negative_duration) self.assertIsNone(self.club.note.last_negative_duration) Transaction.objects.create( source=self.club.note, destination=self.user.note, amount=2 * self.club.note.balance + 100, reason="Club balance is negative", ) self.club.note.refresh_from_db() self.assertIsNotNone(self.club.note.last_negative_duration) def test_api_search(self): response = self.client.get("/api/note/note/") self.assertEqual(response.status_code, 200) response = self.client.get("/api/note/alias/?alias=.*") self.assertEqual(response.status_code, 200) response = self.client.get("/api/note/consumer/") self.assertEqual(response.status_code, 200) response = self.client.get("/api/note/transaction/transaction/") self.assertEqual(response.status_code, 200) response = self.client.get("/api/note/transaction/template/") self.assertEqual(response.status_code, 200) def test_api_alias(self): response = self.client.post("/api/note/alias/", data=dict( name="testalias", note=self.user.note.id, )) self.assertEqual(response.status_code, 201) self.assertTrue(Alias.objects.filter(name="testalias").exists()) alias = Alias.objects.get(name="testalias") response = self.client.patch("/api/note/alias/" + str(alias.pk) + "/", dict(name="test_updated_alias"), content_type="application/json") self.assertEqual(response.status_code, 200) self.assertTrue(Alias.objects.filter(name="test_updated_alias").exists()) response = self.client.delete("/api/note/alias/" + str(alias.pk) + "/") self.assertEqual(response.status_code, 204) class TestNoteAPI(TestAPI): def setUp(self) -> None: super().setUp() membership = Membership.objects.create(club=Club.objects.get(name="BDE"), user=self.user) membership.roles.add(Role.objects.get(name="Respo info")) membership.save() Membership.objects.create(club=Club.objects.get(name="Kfet"), user=self.user) self.user.note.last_negative = timezone.now() self.user.note.save() self.transaction = Transaction.objects.create( source=Note.objects.first(), destination=self.user.note, amount=4200, reason="Test transaction", ) self.user.note.refresh_from_db() Alias.objects.create(note=self.user.note, name="I am a ¢omplex alias") self.category = TemplateCategory.objects.create(name="Test") self.template = TransactionTemplate.objects.create( name="Test", destination=Club.objects.get(name="BDE").note, category=self.category, amount=100, description="Test template", ) def test_alias_api(self): """ Load Alias API page and test all filters and permissions """ self.check_viewset(AliasViewSet, "/api/note/alias/") def test_consumer_api(self): """ Load Consumer API page and test all filters and permissions """ self.check_viewset(ConsumerViewSet, "/api/note/consumer/") def test_note_api(self): """ Load Note API page and test all filters and permissions """ self.check_viewset(NotePolymorphicViewSet, "/api/note/note/") def test_template_category_api(self): """ Load TemplateCategory API page and test all filters and permissions """ self.check_viewset(TemplateCategoryViewSet, "/api/note/transaction/category/") def test_transaction_template_api(self): """ Load TemplateTemplate API page and test all filters and permissions """ self.check_viewset(TransactionTemplateViewSet, "/api/note/transaction/template/") def test_transaction_api(self): """ Load Transaction API page and test all filters and permissions """ self.check_viewset(TransactionViewSet, "/api/note/transaction/transaction/")