Features: 1) Add GatewayManager and GatewayQuerySet to handle advanced gateway filtering and usage checks; 2) Integrate GatewayManager with Gateway model for automatic query filtering; 3) Introduce can_be_used query annotation for gateway availability.
Fixes: 1) Default to a usable `Gateway` when processing new transactions if none is specified. Extra: 1) Add missing import for `GatewayManager` in `payments.models`; 2) Refactor gateway availability logic into the manager and query set for cleaner code organization.
This commit is contained in:
parent
33fbbc049a
commit
3fe3d571bb
3 changed files with 51 additions and 2 deletions
44
payments/managers.py
Normal file
44
payments/managers.py
Normal 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()
|
||||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in a new issue