mirror of
https://github.com/ae-utbm/sith.git
synced 2025-04-29 12:56:47 +00:00
Test pay with card
This commit is contained in:
parent
2a7c1a6438
commit
a31dc8254a
@ -1,5 +1,13 @@
|
|||||||
|
import base64
|
||||||
|
import urllib
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15
|
||||||
|
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey
|
||||||
|
from cryptography.hazmat.primitives.hashes import SHA1
|
||||||
|
from cryptography.hazmat.primitives.serialization import load_pem_private_key
|
||||||
|
from django.conf import settings
|
||||||
from django.contrib.messages import get_messages
|
from django.contrib.messages import get_messages
|
||||||
from django.contrib.messages.constants import DEFAULT_LEVELS
|
from django.contrib.messages.constants import DEFAULT_LEVELS
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
@ -7,12 +15,15 @@ from django.urls import reverse
|
|||||||
from model_bakery import baker
|
from model_bakery import baker
|
||||||
from pytest_django.asserts import assertRedirects
|
from pytest_django.asserts import assertRedirects
|
||||||
|
|
||||||
from core.baker_recipes import subscriber_user
|
from core.baker_recipes import old_subscriber_user, subscriber_user
|
||||||
from counter.baker_recipes import product_recipe
|
from counter.baker_recipes import product_recipe
|
||||||
from counter.models import Product, ProductType
|
from counter.models import Product, ProductType, Selling
|
||||||
from counter.tests.test_counter import force_refill_user
|
from counter.tests.test_counter import force_refill_user
|
||||||
from eboutic.models import Basket, BasketItem
|
from eboutic.models import Basket, BasketItem
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey
|
||||||
|
|
||||||
|
|
||||||
class TestPaymentBase(TestCase):
|
class TestPaymentBase(TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -82,6 +93,22 @@ class TestPaymentSith(TestPaymentBase):
|
|||||||
self.customer.customer.refresh_from_db()
|
self.customer.customer.refresh_from_db()
|
||||||
assert self.customer.customer.amount == Decimal("1")
|
assert self.customer.customer.amount == Decimal("1")
|
||||||
|
|
||||||
|
sellings = Selling.objects.filter(customer=self.customer.customer).order_by(
|
||||||
|
"quantity"
|
||||||
|
)
|
||||||
|
assert len(sellings) == 2
|
||||||
|
assert sellings[0].payment_method == "SITH_ACCOUNT"
|
||||||
|
assert sellings[0].quantity == 1
|
||||||
|
assert sellings[0].unit_price == self.snack.selling_price
|
||||||
|
assert sellings[0].counter.type == "EBOUTIC"
|
||||||
|
assert sellings[0].product == self.snack
|
||||||
|
|
||||||
|
assert sellings[1].payment_method == "SITH_ACCOUNT"
|
||||||
|
assert sellings[1].quantity == 2
|
||||||
|
assert sellings[1].unit_price == self.beer.selling_price
|
||||||
|
assert sellings[1].counter.type == "EBOUTIC"
|
||||||
|
assert sellings[1].product == self.beer
|
||||||
|
|
||||||
def test_not_enough_money(self):
|
def test_not_enough_money(self):
|
||||||
self.client.force_login(self.customer)
|
self.client.force_login(self.customer)
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
@ -120,3 +147,103 @@ class TestPaymentSith(TestPaymentBase):
|
|||||||
)
|
)
|
||||||
self.customer.customer.refresh_from_db()
|
self.customer.customer.refresh_from_db()
|
||||||
assert self.customer.customer.amount == self.basket.total
|
assert self.customer.customer.amount == self.basket.total
|
||||||
|
|
||||||
|
|
||||||
|
class TestPaymentCard(TestPaymentBase):
|
||||||
|
def generate_bank_valid_answer(self, basket: Basket):
|
||||||
|
query = (
|
||||||
|
f"Amount={int(basket.total * 100)}&BasketID={basket.id}&Auto=42&Error=00000"
|
||||||
|
)
|
||||||
|
with open("./eboutic/tests/private_key.pem", "br") as f:
|
||||||
|
PRIVKEY = f.read()
|
||||||
|
with open("./eboutic/tests/public_key.pem") as f:
|
||||||
|
settings.SITH_EBOUTIC_PUB_KEY = f.read()
|
||||||
|
key: RSAPrivateKey = load_pem_private_key(PRIVKEY, None)
|
||||||
|
sig = key.sign(query.encode("utf-8"), PKCS1v15(), 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_success(self):
|
||||||
|
response = self.client.get(self.generate_bank_valid_answer(self.basket))
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.content.decode("utf-8") == "Payment successful"
|
||||||
|
assert Basket.objects.filter(id=self.basket.id).first() is None
|
||||||
|
|
||||||
|
sellings = Selling.objects.filter(customer=self.customer.customer).order_by(
|
||||||
|
"quantity"
|
||||||
|
)
|
||||||
|
assert len(sellings) == 2
|
||||||
|
assert sellings[0].payment_method == "CARD"
|
||||||
|
assert sellings[0].quantity == 1
|
||||||
|
assert sellings[0].unit_price == self.snack.selling_price
|
||||||
|
assert sellings[0].counter.type == "EBOUTIC"
|
||||||
|
assert sellings[0].product == self.snack
|
||||||
|
|
||||||
|
assert sellings[1].payment_method == "CARD"
|
||||||
|
assert sellings[1].quantity == 2
|
||||||
|
assert sellings[1].unit_price == self.beer.selling_price
|
||||||
|
assert sellings[1].counter.type == "EBOUTIC"
|
||||||
|
assert sellings[1].product == self.beer
|
||||||
|
|
||||||
|
def test_buy_subscribe_product(self):
|
||||||
|
customer = old_subscriber_user.make()
|
||||||
|
assert customer.subscriptions.count() == 1
|
||||||
|
assert not customer.subscriptions.first().is_valid_now()
|
||||||
|
|
||||||
|
basket = baker.make(Basket, user=customer)
|
||||||
|
BasketItem.from_product(Product.objects.get(code="2SCOTIZ"), 1, basket).save()
|
||||||
|
assert (
|
||||||
|
self.client.get(self.generate_bank_valid_answer(basket)).status_code == 200
|
||||||
|
)
|
||||||
|
|
||||||
|
assert customer.subscriptions.count() == 2
|
||||||
|
|
||||||
|
subscription = customer.subscriptions.order_by("-subscription_end").first()
|
||||||
|
assert subscription.is_valid_now()
|
||||||
|
assert subscription.subscription_type == "deux-semestres"
|
||||||
|
assert subscription.location == "EBOUTIC"
|
||||||
|
|
||||||
|
def test_buy_refilling(self):
|
||||||
|
BasketItem.from_product(self.refilling, 2, self.basket).save()
|
||||||
|
assert (
|
||||||
|
self.client.get(self.generate_bank_valid_answer(self.basket)).status_code
|
||||||
|
== 200
|
||||||
|
)
|
||||||
|
|
||||||
|
self.customer.customer.refresh_from_db()
|
||||||
|
assert self.customer.customer.amount == self.refilling.selling_price * 2
|
||||||
|
|
||||||
|
def test_multiple_responses(self):
|
||||||
|
bank_response = self.generate_bank_valid_answer(self.basket)
|
||||||
|
assert self.client.get(bank_response).status_code == 200
|
||||||
|
response = self.client.get(bank_response)
|
||||||
|
assert response.status_code == 500
|
||||||
|
assert (
|
||||||
|
response.text
|
||||||
|
== "Basket processing failed with error: SuspiciousOperation('Basket does not exists')"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_unknown_basket(self):
|
||||||
|
bank_response = self.generate_bank_valid_answer(self.basket)
|
||||||
|
self.basket.delete()
|
||||||
|
response = self.client.get(bank_response)
|
||||||
|
assert response.status_code == 500
|
||||||
|
assert (
|
||||||
|
response.text
|
||||||
|
== "Basket processing failed with error: SuspiciousOperation('Basket does not exists')"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_altered_basket(self):
|
||||||
|
bank_response = self.generate_bank_valid_answer(self.basket)
|
||||||
|
BasketItem.from_product(self.snack, 1, self.basket).save()
|
||||||
|
response = self.client.get(bank_response)
|
||||||
|
assert response.status_code == 500
|
||||||
|
assert (
|
||||||
|
response.text == "Basket processing failed with error: "
|
||||||
|
"SuspiciousOperation('Basket total and amount do not match')"
|
||||||
|
)
|
||||||
|
@ -1,173 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright 2016,2017
|
|
||||||
# - Skia <skia@libskia.so>
|
|
||||||
# - Maréchal <thgirod@hotmail.com
|
|
||||||
#
|
|
||||||
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
|
|
||||||
# http://ae.utbm.fr.
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify it under
|
|
||||||
# the terms of the GNU General Public License a published by the Free Software
|
|
||||||
# Foundation; either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
#
|
|
||||||
#
|
|
||||||
import base64
|
|
||||||
import json
|
|
||||||
import urllib
|
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
|
|
||||||
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.test import TestCase
|
|
||||||
from django.urls import reverse
|
|
||||||
|
|
||||||
from core.models import User
|
|
||||||
from counter.models import Counter, Customer, Product, Selling
|
|
||||||
from eboutic.models import Basket, BasketItem
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey
|
|
||||||
|
|
||||||
|
|
||||||
class TestEboutic(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()
|
|
||||||
BasketItem.from_product(self.barbar, 3, basket).save()
|
|
||||||
BasketItem.from_product(self.cotis, 1, basket).save()
|
|
||||||
return basket
|
|
||||||
|
|
||||||
def generate_bank_valid_answer(self) -> str:
|
|
||||||
basket = Basket.from_session(self.client.session)
|
|
||||||
basket_id = basket.id
|
|
||||||
amount = int(basket.total * 100)
|
|
||||||
query = f"Amount={amount}&BasketID={basket_id}&Auto=42&Error=00000"
|
|
||||||
with open("./eboutic/tests/private_key.pem", "br") as f:
|
|
||||||
PRIVKEY = f.read()
|
|
||||||
with open("./eboutic/tests/public_key.pem") as f:
|
|
||||||
settings.SITH_EBOUTIC_PUB_KEY = f.read()
|
|
||||||
key: RSAPrivateKey = load_pem_private_key(PRIVKEY, None)
|
|
||||||
sig = key.sign(query.encode("utf-8"), PKCS1v15(), 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_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.text,
|
|
||||||
)
|
|
||||||
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.text == "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
|
|
||||||
msg = (
|
|
||||||
"Basket processing failed with error: "
|
|
||||||
"SuspiciousOperation('Basket total and amount do not match'"
|
|
||||||
)
|
|
||||||
assert msg 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
|
|
Loading…
x
Reference in New Issue
Block a user