Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add discounts #182

Draft
wants to merge 3 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion insalan/payment/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from django.http import HttpResponse
from django.utils.translation import gettext_lazy as _

from .models import Product, Transaction, Payment, TransactionStatus
from .models import Product, Transaction, Payment, TransactionStatus, Discount


class ProductAdmin(admin.ModelAdmin):
Expand Down Expand Up @@ -123,3 +123,15 @@ def has_delete_permission(self, _request, _obj=None):


admin.site.register(Transaction, TransactionAdmin)

class DiscountAdmin(admin.ModelAdmin):
"""
Admin handler for Discounts
"""

list_display = ("id", "discount", "user", "product", "used")
search_fields = ["id", "discount", "user", "product", "reason"]



admin.site.register(Discount, DiscountAdmin)
65 changes: 65 additions & 0 deletions insalan/payment/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ def can_be_bought_now(self) -> bool:
"""Returns whether or not the product can be bought now"""
return self.available_from <= timezone.now() <= self.available_until

def __str__(self):
"""
Return the name of the product
"""
return str(self.name)


class Payment(models.Model):
"""
Expand Down Expand Up @@ -161,6 +167,11 @@ class Meta:
decimal_places=2,
verbose_name=_("Montant"),
)
discounts = models.ManyToManyField(
"Discount",
blank=True,
verbose_name=_("Réductions")
)

@staticmethod
def new(**data):
Expand Down Expand Up @@ -326,6 +337,10 @@ def validate_transaction(self):

self.payment_status = TransactionStatus.SUCCEEDED
self.last_modification_date = timezone.make_aware(datetime.now())
# For each discount, mark it as used
for discount in self.discounts.all():
discount.use()

self.save()
logger.info("Transaction %s succeeded", self.id)
self.run_success_hooks()
Expand Down Expand Up @@ -378,3 +393,53 @@ class Meta:
null=True,
)
count = models.IntegerField(default=1, editable=True, verbose_name=_("Quantité"))

# Discount

class DiscountAlreadyUsedError(Exception):
"""Error raised when trying to use an already used discount"""

class Discount(models.Model):
"""
A discount is a temporary reduction of the price of a product

A discount is tied to a user, a product and can be used only once
"""

class Meta:
"""Meta information"""

verbose_name = _("Réduction")
verbose_name_plural = _("Réductions")

id: int
user = models.ForeignKey(
User, null=True, on_delete=models.SET_NULL, verbose_name=_("Utilisateur")
)
product = models.ForeignKey(
Product, null=True, on_delete=models.SET_NULL, verbose_name=_("Produit")
)
discount = models.DecimalField(
null=False, max_digits=5, decimal_places=2, verbose_name=_("Réduction")
)
reason = models.CharField(max_length=200, verbose_name=_("Motif"))
creation_date = models.DateTimeField(
verbose_name=_("Date de création"),
editable=False,
default=timezone.now
)
used = models.BooleanField(default=False, verbose_name=_("Utilisé"))
used_date = models.DateTimeField(
verbose_name=_("Date d'utilisation"),
editable=False,
null=True,
blank=True
)

def use(self):
"""Use the discount"""
if self.used:
raise DiscountAlreadyUsedError("Discount already used")
self.used = True
KwikKill marked this conversation as resolved.
Show resolved Hide resolved
self.used_date = timezone.make_aware(datetime.now())
self.save()
17 changes: 15 additions & 2 deletions insalan/payment/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import insalan.settings as app_settings
import insalan.payment.serializers as serializers

from .models import Transaction, TransactionStatus, Product, Payment
from .models import Transaction, TransactionStatus, Product, Payment, Discount
from .tokens import Token

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -425,9 +425,22 @@ def create(self, request):
status=status.HTTP_400_BAD_REQUEST,
)

amount = transaction_obj.amount

# If the user has a discount for some products, apply them
for product in transaction_obj.products.all():
discounts = Discount.objects.filter(user=payer, product=product, used=False)
for discount in discounts:
# Check if the discount is applicable
if amount >= discount.discount:
amount -= discount.discount

# Add the discount to the transaction object
transaction_obj.discounts.add(discount)

# helloasso intent
helloasso_amount = int(
transaction_obj.amount * 100
amount * 100
) # helloasso reads prices in cents
intent_body = {
"totalAmount": helloasso_amount,
Expand Down
6 changes: 3 additions & 3 deletions insalan/tournament/models/tournament.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ def save(self, *args, **kwargs):
if self.player_online_product is None:
prod = Product.objects.create(
price=self.player_price_online,
name=_(f"Place {self.name} Joueur en ligne"),
name=_(f"Place {self.name} Joueur en ligne - {self.event.name}"),
desc=_(f"Inscription au tournoi {self.name} joueur"),
category=ProductCategory.REGISTRATION_PLAYER,
associated_tournament=self,
Expand All @@ -212,7 +212,7 @@ def save(self, *args, **kwargs):
if self.manager_online_product is None:
prod = Product.objects.create(
price=self.manager_price_online,
name=_(f"Place {self.name} manager en ligne"),
name=_(f"Place {self.name} manager en ligne - {self.event.name}"),
desc=_(f"Inscription au tournoi {self.name} manager"),
category=ProductCategory.REGISTRATION_MANAGER,
associated_tournament=self,
Expand All @@ -229,7 +229,7 @@ def save(self, *args, **kwargs):
if self.substitute_online_product is None:
prod = Product.objects.create(
price=self.substitute_price_online,
name=_(f"Place {self.name} remplaçant en ligne"),
name=_(f"Place {self.name} remplaçant en ligne - {self.event.name}"),
desc=_(f"Inscription au tournoi {self.name} remplaçant"),
category=ProductCategory.REGISTRATION_SUBSTITUTE,
associated_tournament=self,
Expand Down
Loading