Sith/eboutic/tests.py
2024-06-26 19:17:57 +02:00

244 lines
10 KiB
Python

# -*- coding:utf-8 -*-
#
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
# All contributors are listed in the CONTRIBUTORS file.
#
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
#
# You can find the whole source code at https://github.com/ae-utbm/sith3
#
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
#
# PREVIOUSLY LICENSED UNDER THE MIT LICENSE,
# SEE : https://raw.githubusercontent.com/ae-utbm/sith3/master/LICENSE.old
# OR WITHIN THE LOCAL FILE "LICENSE.old"
#
import base64
import json
import urllib
from django.conf import settings
from django.db.models import Max
from django.test import TestCase
from django.urls import reverse
from OpenSSL import crypto
from core.models import User
from counter.models import Counter, Customer, Product, Selling
from eboutic.models import Basket
class EbouticTest(TestCase):
@classmethod
def setUpTestData(cls):
cls.barbar = Product.objects.get(code="BARB")
cls.refill = Product.objects.get(code="15REFILL")
cls.cotis = Product.objects.get(code="1SCOTIZ")
cls.eboutic = Counter.objects.get(name="Eboutic")
cls.skia = User.objects.get(username="skia")
cls.subscriber = User.objects.get(username="subscriber")
cls.old_subscriber = User.objects.get(username="old_subscriber")
cls.public = User.objects.get(username="public")
def get_busy_basket(self, user) -> Basket:
"""
Create and return a basket with 3 barbar and 1 cotis in it.
Edit the client session to store the basket id in it
"""
session = self.client.session
basket = Basket.objects.create(user=user)
session["basket_id"] = basket.id
session.save()
basket.add_product(self.barbar, 3)
basket.add_product(self.cotis)
return basket
def generate_bank_valid_answer(self) -> str:
basket = Basket.from_session(self.client.session)
basket_id = basket.id
amount = int(basket.get_total() * 100)
query = f"Amount={amount}&BasketID={basket_id}&Auto=42&Error=00000"
with open("./eboutic/tests/private_key.pem") as f:
PRIVKEY = f.read()
with open("./eboutic/tests/public_key.pem") as f:
settings.SITH_EBOUTIC_PUB_KEY = f.read()
privkey = crypto.load_privatekey(crypto.FILETYPE_PEM, PRIVKEY)
sig = crypto.sign(privkey, query.encode("utf-8"), "sha1")
b64sig = base64.b64encode(sig).decode("ascii")
url = reverse("eboutic:etransation_autoanswer") + "?%s&Sig=%s" % (
query,
urllib.parse.quote_plus(b64sig),
)
return url
def test_buy_with_sith_account(self):
self.client.force_login(self.subscriber)
self.subscriber.customer.amount = 100 # give money before test
self.subscriber.customer.save()
basket = self.get_busy_basket(self.subscriber)
amount = basket.get_total()
response = self.client.post(reverse("eboutic:pay_with_sith"))
self.assertRedirects(response, "/eboutic/pay/success/")
new_balance = Customer.objects.get(user=self.subscriber).amount
assert float(new_balance) == 100 - amount
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_buy_with_sith_account_no_money(self):
self.client.force_login(self.subscriber)
basket = self.get_busy_basket(self.subscriber)
initial = basket.get_total() - 1 # just not enough to complete the sale
self.subscriber.customer.amount = initial
self.subscriber.customer.save()
response = self.client.post(reverse("eboutic:pay_with_sith"))
self.assertRedirects(response, "/eboutic/pay/failure/")
new_balance = Customer.objects.get(user=self.subscriber).amount
assert float(new_balance) == initial
# this cookie should be removed after payment
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(
"<tr><td>Cotis 2 semestres</td><td>1</td><td>28.00 €</td></tr>",
response.content.decode(),
)
self.assertInHTML(
"<tr><td>Barbar</td><td>3</td><td>1.70 €</td></tr>",
response.content.decode(),
)
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.get_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(
reverse("core:user_profile", kwargs={"user_id": self.old_subscriber.id})
)
assert "Non cotisant" in str(response.content)
self.client.cookies["basket_items"] = """[
{"id": 2, "name": "Cotis 2 semestres", "quantity": 1, "unit_price": 28}
]"""
response = self.client.get(reverse("eboutic:command"))
self.assertInHTML(
"<tr><td>Cotis 2 semestres</td><td>1</td><td>28.00 €</td></tr>",
response.content.decode(),
)
basket = Basket.objects.get(id=self.client.session["basket_id"])
assert basket.items.count() == 1
response = self.client.get(self.generate_bank_valid_answer())
assert response.status_code == 200
assert response.content.decode("utf-8") == "Payment successful"
subscriber = User.objects.get(id=self.old_subscriber.id)
assert subscriber.subscriptions.count() == 2
sub = subscriber.subscriptions.order_by("-subscription_end").first()
assert sub.is_valid_now()
assert sub.member == subscriber
assert sub.subscription_type == "deux-semestres"
assert sub.location == "EBOUTIC"
def test_buy_refill_product_with_credit_card(self):
self.client.force_login(self.subscriber)
# basket contains 1 refill item worth 15€
self.client.cookies["basket_items"] = json.dumps(
[{"id": 3, "name": "Rechargement 15 €", "quantity": 1, "unit_price": 15}]
)
initial_balance = self.subscriber.customer.amount
self.client.get(reverse("eboutic:command"))
url = self.generate_bank_valid_answer()
response = self.client.get(url)
assert response.status_code == 200
assert response.content.decode() == "Payment successful"
new_balance = Customer.objects.get(user=self.subscriber).amount
assert new_balance == initial_balance + 15
def test_alter_basket_after_submission(self):
self.client.force_login(self.subscriber)
self.client.cookies["basket_items"] = json.dumps(
[{"id": 4, "name": "Barbar", "quantity": 1, "unit_price": 1.7}]
)
self.client.get(reverse("eboutic:command"))
et_answer_url = self.generate_bank_valid_answer()
self.client.cookies["basket_items"] = json.dumps(
[ # alter basket
{"id": 4, "name": "Barbar", "quantity": 3, "unit_price": 1.7}
]
)
self.client.get(reverse("eboutic:command"))
response = self.client.get(et_answer_url)
assert response.status_code == 500
assert (
"Basket processing failed with error: SuspiciousOperation('Basket total and amount do not match'"
in response.content.decode("utf-8"),
)
def test_buy_simple_product_with_credit_card(self):
self.client.force_login(self.subscriber)
self.client.cookies["basket_items"] = json.dumps(
[{"id": 4, "name": "Barbar", "quantity": 1, "unit_price": 1.7}]
)
self.client.get(reverse("eboutic:command"))
et_answer_url = self.generate_bank_valid_answer()
response = self.client.get(et_answer_url)
assert response.status_code == 200
assert response.content.decode("utf-8") == "Payment successful"
selling = (
Selling.objects.filter(customer=self.subscriber.customer)
.order_by("-date")
.first()
)
assert selling.payment_method == "CARD"
assert selling.quantity == 1
assert selling.unit_price == self.barbar.selling_price
assert selling.counter.type == "EBOUTIC"
assert selling.product == self.barbar