Compare commits

...

4 commits

Author SHA1 Message Date
1a63acee32 Merge pull request 'FIX(promotions): default event status promotion_amount to 0' (#2) from feature/allow-users into master
Reviewed-on: #2
2026-08-03 11:04:17 -04:00
54de7fdb48 PERF(promotions): collapse allowed-user check into a single query
Fold the restricted-recipient access check into the recipients
queryset itself via Q(public OR restricted-and-allowed), joining
against AllowedUser instead of running a separate lookup query.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-03 18:21:23 +03:30
33aa0ed1b4 PERF(promotions): batch allowed-user lookup in get_configured_promotion_amount
Checking each recipient via Recipient.is_user_allowed() inside the
loop issued one AllowedUser query per restricted recipient (N+1).
Fetch all matching AllowedUser rows for the plan's recipients in a
single query up front instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-03 17:55:42 +03:30
ac37f15bea FIX(promotions): default event status promotion_amount to 0
get_event_status_for_user returned None whenever the event was
already processed, no plan matched, or the user lacked access to the
recipient. Callers now always get a concrete amount: the real payout
if accessible, 0 otherwise.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-03 17:33:59 +03:30

View file

@ -3,7 +3,7 @@ import uuid
from django.conf import settings
from django.contrib.postgres.indexes import GinIndex
from django.db import models, transaction
from django.db.models import F
from django.db.models import F, Q
from django.utils import timezone
from django_minio_backend import MinioBackend, iso_date_prefix
@ -136,10 +136,16 @@ class Plan(BaseModel):
return self.title
def get_configured_promotion_amount(self, user_uuid=None):
access_filter = Q(access_type=RecipientTypeChoices.PUBLIC)
if user_uuid:
access_filter |= Q(access_type=RecipientTypeChoices.RESTRICTED, allowed_users__user__uuid=user_uuid)
recipients = self.recipients.filter(
recipient_uuid_field='->event:user' #TODO: instead of hard code use better soloution
).filter(access_filter).distinct()
amount = 0
for recipient in self.recipients.filter(recipient_uuid_field='->event:user'): #TODO: instead of hard code use better soloution
if not recipient.is_user_allowed(user_uuid):
continue
for recipient in recipients:
base_amount, promotion_amount = recipient.get_promotion_amount()
amount += promotion_amount
return amount
@ -393,7 +399,7 @@ class PromotionQuerySet(models.QuerySet):
def get_event_status_for_user(user_uuid, event_label):
processed = Promotion.objects.is_processed_for_user(user_uuid, event_label)
promotion_amount = None
promotion_amount = 0
if not processed:
plan = Plan.objects.filter(event_list__icontains=event_label).first()
if plan: