mirror of
https://github.com/ae-utbm/sith.git
synced 2025-04-29 12:56:47 +00:00
Test pay with sith
This commit is contained in:
parent
8af6af1303
commit
2a7c1a6438
@ -47,6 +47,10 @@ from counter.fields import CurrencyField
|
|||||||
from subscription.models import Subscription
|
from subscription.models import Subscription
|
||||||
|
|
||||||
|
|
||||||
|
def get_eboutic() -> Counter:
|
||||||
|
return Counter.objects.filter(type="EBOUTIC").order_by("id").first()
|
||||||
|
|
||||||
|
|
||||||
class CustomerQuerySet(models.QuerySet):
|
class CustomerQuerySet(models.QuerySet):
|
||||||
def update_amount(self) -> int:
|
def update_amount(self) -> int:
|
||||||
"""Update the amount of all customers selected by this queryset.
|
"""Update the amount of all customers selected by this queryset.
|
||||||
|
@ -28,12 +28,20 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
|
|
||||||
from core.models import User
|
from core.models import User
|
||||||
from counter.fields import CurrencyField
|
from counter.fields import CurrencyField
|
||||||
from counter.models import BillingInfo, Counter, Customer, Product, Refilling, Selling
|
from counter.models import (
|
||||||
|
BillingInfo,
|
||||||
|
Counter,
|
||||||
|
Customer,
|
||||||
|
Product,
|
||||||
|
Refilling,
|
||||||
|
Selling,
|
||||||
|
get_eboutic,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_eboutic_products(user: User) -> list[Product]:
|
def get_eboutic_products(user: User) -> list[Product]:
|
||||||
products = (
|
products = (
|
||||||
Counter.objects.get(type="EBOUTIC")
|
get_eboutic()
|
||||||
.products.filter(product_type__isnull=False)
|
.products.filter(product_type__isnull=False)
|
||||||
.filter(archived=False)
|
.filter(archived=False)
|
||||||
.filter(limit_age__lte=user.age)
|
.filter(limit_age__lte=user.age)
|
||||||
@ -102,13 +110,6 @@ class Basket(models.Model):
|
|||||||
)["total"]
|
)["total"]
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_session(cls, session) -> Basket | None:
|
|
||||||
"""The basket stored in the session object, if it exists."""
|
|
||||||
if "basket_id" in session:
|
|
||||||
return cls.objects.filter(id=session["basket_id"]).first()
|
|
||||||
return None
|
|
||||||
|
|
||||||
def generate_sales(self, counter, seller: User, payment_method: str):
|
def generate_sales(self, counter, seller: User, payment_method: str):
|
||||||
"""Generate a list of sold items corresponding to the items
|
"""Generate a list of sold items corresponding to the items
|
||||||
of this basket WITHOUT saving them NOR deleting the basket.
|
of this basket WITHOUT saving them NOR deleting the basket.
|
||||||
|
@ -4,6 +4,14 @@
|
|||||||
<h3>{% trans %}Eboutic{% endtrans %}</h3>
|
<h3>{% trans %}Eboutic{% endtrans %}</h3>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
{% if messages %}
|
||||||
|
{% for message in messages %}
|
||||||
|
<div class="alert alert-{{ message.tags }}">
|
||||||
|
{{ message }}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if success %}
|
{% if success %}
|
||||||
{% trans %}Payment successful{% endtrans %}
|
{% trans %}Payment successful{% endtrans %}
|
||||||
{% else %}
|
{% else %}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import pytest
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.test.client import Client
|
from django.test.client import Client
|
||||||
@ -9,11 +10,20 @@ from pytest_django.asserts import assertRedirects
|
|||||||
from core.baker_recipes import subscriber_user
|
from core.baker_recipes import subscriber_user
|
||||||
from core.models import Group, User
|
from core.models import Group, User
|
||||||
from counter.baker_recipes import product_recipe
|
from counter.baker_recipes import product_recipe
|
||||||
from counter.models import Counter, ProductType
|
from counter.models import Counter, ProductType, get_eboutic
|
||||||
from counter.tests.test_counter import BasketItem
|
from counter.tests.test_counter import BasketItem
|
||||||
from eboutic.models import Basket
|
from eboutic.models import Basket
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_get_eboutic():
|
||||||
|
assert Counter.objects.get(name="Eboutic") == get_eboutic()
|
||||||
|
|
||||||
|
baker.make(Counter, type="EBOUTIC")
|
||||||
|
|
||||||
|
assert Counter.objects.get(name="Eboutic") == get_eboutic()
|
||||||
|
|
||||||
|
|
||||||
class TestEboutic(TestCase):
|
class TestEboutic(TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -51,7 +61,7 @@ class TestEboutic(TestCase):
|
|||||||
cls.new_customer.groups.add(cls.group_public)
|
cls.new_customer.groups.add(cls.group_public)
|
||||||
cls.new_customer_adult.groups.add(cls.group_public)
|
cls.new_customer_adult.groups.add(cls.group_public)
|
||||||
|
|
||||||
cls.eboutic = Counter.objects.get(name="Eboutic")
|
cls.eboutic = get_eboutic()
|
||||||
cls.eboutic.products.add(cls.cotiz, cls.beer, cls.snack)
|
cls.eboutic.products.add(cls.cotiz, cls.beer, cls.snack)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
122
eboutic/tests/test_payment.py
Normal file
122
eboutic/tests/test_payment.py
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
|
from django.contrib.messages import get_messages
|
||||||
|
from django.contrib.messages.constants import DEFAULT_LEVELS
|
||||||
|
from django.test import TestCase
|
||||||
|
from django.urls import reverse
|
||||||
|
from model_bakery import baker
|
||||||
|
from pytest_django.asserts import assertRedirects
|
||||||
|
|
||||||
|
from core.baker_recipes import subscriber_user
|
||||||
|
from counter.baker_recipes import product_recipe
|
||||||
|
from counter.models import Product, ProductType
|
||||||
|
from counter.tests.test_counter import force_refill_user
|
||||||
|
from eboutic.models import Basket, BasketItem
|
||||||
|
|
||||||
|
|
||||||
|
class TestPaymentBase(TestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
cls.customer = subscriber_user.make()
|
||||||
|
cls.basket = baker.make(Basket, user=cls.customer)
|
||||||
|
cls.refilling = Product.objects.get(code="15REFILL")
|
||||||
|
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
|
||||||
|
BasketItem.from_product(cls.snack, 1, cls.basket).save()
|
||||||
|
BasketItem.from_product(cls.beer, 2, cls.basket).save()
|
||||||
|
|
||||||
|
|
||||||
|
class TestPaymentSith(TestPaymentBase):
|
||||||
|
def test_anonymous(self):
|
||||||
|
assert (
|
||||||
|
self.client.post(
|
||||||
|
reverse("eboutic:pay_with_sith", kwargs={"basket_id": self.basket.id}),
|
||||||
|
).status_code
|
||||||
|
== 403
|
||||||
|
)
|
||||||
|
assert Basket.objects.filter(id=self.basket.id).first() is not None
|
||||||
|
|
||||||
|
def test_unauthorized(self):
|
||||||
|
self.client.force_login(subscriber_user.make())
|
||||||
|
assert (
|
||||||
|
self.client.post(
|
||||||
|
reverse("eboutic:pay_with_sith", kwargs={"basket_id": self.basket.id}),
|
||||||
|
).status_code
|
||||||
|
== 403
|
||||||
|
)
|
||||||
|
assert Basket.objects.filter(id=self.basket.id).first() is not None
|
||||||
|
|
||||||
|
def test_not_found(self):
|
||||||
|
self.client.force_login(self.customer)
|
||||||
|
assert (
|
||||||
|
self.client.post(
|
||||||
|
reverse(
|
||||||
|
"eboutic:pay_with_sith", kwargs={"basket_id": self.basket.id + 1}
|
||||||
|
),
|
||||||
|
).status_code
|
||||||
|
== 404
|
||||||
|
)
|
||||||
|
assert Basket.objects.filter(id=self.basket.id).first() is not None
|
||||||
|
|
||||||
|
def test_buy_success(self):
|
||||||
|
self.client.force_login(self.customer)
|
||||||
|
force_refill_user(self.customer, self.basket.total + 1)
|
||||||
|
assertRedirects(
|
||||||
|
self.client.post(
|
||||||
|
reverse("eboutic:pay_with_sith", kwargs={"basket_id": self.basket.id}),
|
||||||
|
),
|
||||||
|
reverse("eboutic:payment_result", kwargs={"result": "success"}),
|
||||||
|
)
|
||||||
|
assert Basket.objects.filter(id=self.basket.id).first() is None
|
||||||
|
self.customer.customer.refresh_from_db()
|
||||||
|
assert self.customer.customer.amount == Decimal("1")
|
||||||
|
|
||||||
|
def test_not_enough_money(self):
|
||||||
|
self.client.force_login(self.customer)
|
||||||
|
response = self.client.post(
|
||||||
|
reverse("eboutic:pay_with_sith", kwargs={"basket_id": self.basket.id}),
|
||||||
|
)
|
||||||
|
assertRedirects(
|
||||||
|
response,
|
||||||
|
reverse("eboutic:payment_result", kwargs={"result": "failure"}),
|
||||||
|
)
|
||||||
|
|
||||||
|
messages = list(get_messages(response.wsgi_request))
|
||||||
|
assert len(messages) == 1
|
||||||
|
assert messages[0].level == DEFAULT_LEVELS["ERROR"]
|
||||||
|
assert messages[0].message == "Solde insuffisant"
|
||||||
|
|
||||||
|
assert Basket.objects.filter(id=self.basket.id).first() is not None
|
||||||
|
|
||||||
|
def test_refilling_in_basket(self):
|
||||||
|
BasketItem.from_product(self.refilling, 1, self.basket).save()
|
||||||
|
self.client.force_login(self.customer)
|
||||||
|
force_refill_user(self.customer, self.basket.total)
|
||||||
|
response = self.client.post(
|
||||||
|
reverse("eboutic:pay_with_sith", kwargs={"basket_id": self.basket.id}),
|
||||||
|
)
|
||||||
|
assertRedirects(
|
||||||
|
response,
|
||||||
|
reverse("eboutic:payment_result", kwargs={"result": "failure"}),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert Basket.objects.filter(id=self.basket.id).first() is not None
|
||||||
|
messages = list(get_messages(response.wsgi_request))
|
||||||
|
assert messages[0].level == DEFAULT_LEVELS["ERROR"]
|
||||||
|
assert (
|
||||||
|
messages[0].message
|
||||||
|
== "Vous ne pouvez pas acheter un rechargement avec de l'argent du sith"
|
||||||
|
)
|
||||||
|
self.customer.customer.refresh_from_db()
|
||||||
|
assert self.customer.customer.amount == self.basket.total
|
@ -85,33 +85,6 @@ class TestEboutic(TestCase):
|
|||||||
)
|
)
|
||||||
return url
|
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.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.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_buy_subscribe_product_with_credit_card(self):
|
def test_buy_subscribe_product_with_credit_card(self):
|
||||||
self.client.force_login(self.old_subscriber)
|
self.client.force_login(self.old_subscriber)
|
||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
|
@ -32,7 +32,7 @@ from django.contrib.auth.mixins import (
|
|||||||
LoginRequiredMixin,
|
LoginRequiredMixin,
|
||||||
)
|
)
|
||||||
from django.contrib.messages.views import SuccessMessageMixin
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
from django.core.exceptions import SuspiciousOperation
|
from django.core.exceptions import SuspiciousOperation, ValidationError
|
||||||
from django.db import DatabaseError, transaction
|
from django.db import DatabaseError, transaction
|
||||||
from django.db.models.fields import forms
|
from django.db.models.fields import forms
|
||||||
from django.db.utils import cached_property
|
from django.db.utils import cached_property
|
||||||
@ -48,7 +48,7 @@ from django_countries.fields import Country
|
|||||||
from core.auth.mixins import CanViewMixin, IsSubscriberMixin
|
from core.auth.mixins import CanViewMixin, IsSubscriberMixin
|
||||||
from core.views.mixins import FragmentMixin, UseFragmentsMixin
|
from core.views.mixins import FragmentMixin, UseFragmentsMixin
|
||||||
from counter.forms import BaseBasketForm, BillingInfoForm, ProductForm
|
from counter.forms import BaseBasketForm, BillingInfoForm, ProductForm
|
||||||
from counter.models import BillingInfo, Counter, Customer, Product, Selling
|
from counter.models import BillingInfo, Customer, Product, Selling, get_eboutic
|
||||||
from eboutic.models import (
|
from eboutic.models import (
|
||||||
Basket,
|
Basket,
|
||||||
BasketItem,
|
BasketItem,
|
||||||
@ -90,7 +90,7 @@ class EbouticMainView(LoginRequiredMixin, FormView):
|
|||||||
kwargs = super().get_form_kwargs()
|
kwargs = super().get_form_kwargs()
|
||||||
kwargs["form_kwargs"] = {
|
kwargs["form_kwargs"] = {
|
||||||
"customer": self.customer,
|
"customer": self.customer,
|
||||||
"counter": Counter.objects.get(type="EBOUTIC"),
|
"counter": get_eboutic(),
|
||||||
"allowed_products": {product.id: product for product in self.products},
|
"allowed_products": {product.id: product for product in self.products},
|
||||||
}
|
}
|
||||||
return kwargs
|
return kwargs
|
||||||
@ -246,9 +246,9 @@ class EbouticPayWithSith(CanViewMixin, SingleObjectMixin, View):
|
|||||||
self.request,
|
self.request,
|
||||||
_("You can't buy a refilling with sith money"),
|
_("You can't buy a refilling with sith money"),
|
||||||
)
|
)
|
||||||
return redirect("eboutic:main")
|
return redirect("eboutic:payment_result", "failure")
|
||||||
|
|
||||||
eboutic = Counter.objects.get(type="EBOUTIC")
|
eboutic = get_eboutic()
|
||||||
sales = basket.generate_sales(eboutic, basket.user, "SITH_ACCOUNT")
|
sales = basket.generate_sales(eboutic, basket.user, "SITH_ACCOUNT")
|
||||||
try:
|
try:
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
@ -260,6 +260,8 @@ class EbouticPayWithSith(CanViewMixin, SingleObjectMixin, View):
|
|||||||
return redirect("eboutic:payment_result", "success")
|
return redirect("eboutic:payment_result", "success")
|
||||||
except DatabaseError as e:
|
except DatabaseError as e:
|
||||||
sentry_sdk.capture_exception(e)
|
sentry_sdk.capture_exception(e)
|
||||||
|
except ValidationError as e:
|
||||||
|
messages.error(self.request, e.message)
|
||||||
return redirect("eboutic:payment_result", "failure")
|
return redirect("eboutic:payment_result", "failure")
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user