Merge branch 'main' into storefront-nuxt

This commit is contained in:
Egor Pavlovich Gorbunov 2025-10-24 13:07:15 +03:00
commit 1d1213813c
3 changed files with 55 additions and 2 deletions

44
payments/managers.py Normal file
View file

@ -0,0 +1,44 @@
from django.db.models import BooleanField, Case, F, Manager, Q, QuerySet, Sum, Value, When
from django.db.models.functions import Coalesce
from django.utils.timezone import now
class GatewayQuerySet(QuerySet):
def with_usage_sums(self) -> QuerySet:
today = now().date()
current_month_start = today.replace(day=1)
return self.annotate(
daily_sum=Coalesce(Sum("transactions__amount", filter=Q(transactions__created__date=today)), Value(0.0)),
monthly_sum=Coalesce(
Sum("transactions__amount", filter=Q(transactions__created__gte=current_month_start)), Value(0.0)
),
)
def can_be_used(self) -> QuerySet:
qs = self.with_usage_sums()
qs = qs.annotate(
daily_ok=Case(
When(daily_limit=0, then=Value(True)),
When(daily_sum__lt=F("daily_limit"), then=Value(True)),
default=Value(False),
output_field=BooleanField(),
),
monthly_ok=Case(
When(monthly_limit=0, then=Value(True)),
When(monthly_sum__lt=F("monthly_limit"), then=Value(True)),
default=Value(False),
output_field=BooleanField(),
),
)
return qs.annotate(
can_be_used=Case(
When(daily_ok=True, monthly_ok=True, is_active=True, then=Value(True)),
default=Value(False),
output_field=BooleanField(),
)
).order_by("-priority")
class GatewayManager(Manager.from_queryset(GatewayQuerySet)):
def get_queryset(self) -> QuerySet:
return super().get_queryset().can_be_used()

View file

@ -20,6 +20,7 @@ from django.utils.translation import gettext_lazy as _
from core.abstract import NiceModel
from evibes.utils.misc import create_object
from payments.gateways import AbstractGateway
from payments.managers import GatewayManager
class Transaction(NiceModel):
@ -87,6 +88,7 @@ class Balance(NiceModel):
class Gateway(NiceModel):
objects = GatewayManager()
name = CharField(max_length=20, null=False, blank=False, verbose_name=_("name"))
default_currency = CharField(
max_length=4,
@ -138,6 +140,9 @@ class Gateway(NiceModel):
@property
def can_be_used(self) -> bool:
if not self.is_active:
return False
today = now().date()
current_month_start = today.replace(day=1)
@ -152,6 +157,10 @@ class Gateway(NiceModel):
return daily_ok and monthly_ok
@can_be_used.setter
def can_be_used(self, value: bool):
self.__dict__["can_be_used"] = value
def get_integration_class_object(self, raise_exc: bool = True) -> Type[AbstractGateway] | None:
if not self.integration_path:
if raise_exc:

View file

@ -5,7 +5,7 @@ from typing import Any
from django.db.models.signals import post_save
from django.dispatch import receiver
from payments.models import Balance, Transaction
from payments.models import Balance, Transaction, Gateway
from payments.utils.emailing import balance_deposit_email
from vibes_auth.models import User
@ -24,7 +24,7 @@ def create_balance_on_user_creation_signal(instance: User, created: bool, **kwar
def process_transaction_changes(instance: Transaction, created: bool, **kwargs: dict[Any, Any]) -> None:
if created:
if not instance.gateway:
raise ValueError("gateway is required to process a transaction")
instance.gateway = Gateway.objects.can_be_used().first()
try:
gateway = instance.gateway.get_integration_class_object()
gateway.process_transaction(instance)