diff --git a/apps/promotions/handlers.py b/apps/promotions/handlers.py index c9caf56..dac6713 100644 --- a/apps/promotions/handlers.py +++ b/apps/promotions/handlers.py @@ -9,13 +9,13 @@ from utils.clients.wallet_client import deposit_to_user_wallet_submit, deposit_t logger = logging.getLogger("promotion_handler") class PromotionTypeChoices(models.TextChoices): - WALLET_PERCENTAGE = 'wallet percentage', _('Wallet percentage') + PERCENTAGE = 'percentage', _('percentage') OTHERS = 'others', _('others') @enum_property def handler(self): - if self.name == self.WALLET_PERCENTAGE.name: - return WalletPercentageHandler + if self.name == self.PERCENTAGE.name: + return PercentageHandler elif self.name == self.OTHERS.name: return OtherHandler @@ -37,7 +37,7 @@ class BasePromotionHandler: raise NotImplementedError() -class WalletPercentageHandler(BasePromotionHandler): +class PercentageHandler(BasePromotionHandler): def calculate(self, **kwargs): base_amount = kwargs.get('base_amount', 0) @@ -49,6 +49,7 @@ class WalletPercentageHandler(BasePromotionHandler): return promotion_amount def promote(self, promotion, **kwargs): + pass payee_type = self.policy.get('payee_type') payee_uuid = self.policy.get('payee_uuid') diff --git a/apps/promotions/migrations/0006_rename_details_event_data.py b/apps/promotions/migrations/0006_rename_details_event_data.py new file mode 100644 index 0000000..18a5685 --- /dev/null +++ b/apps/promotions/migrations/0006_rename_details_event_data.py @@ -0,0 +1,18 @@ +# Generated by Django 5.2.6 on 2025-09-18 11:22 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('promotions', '0005_event_plan_event_list'), + ] + + operations = [ + migrations.RenameField( + model_name='event', + old_name='details', + new_name='data', + ), + ] diff --git a/apps/promotions/migrations/0007_plan_max_amount_plan_min_amount_and_more.py b/apps/promotions/migrations/0007_plan_max_amount_plan_min_amount_and_more.py new file mode 100644 index 0000000..452dbdc --- /dev/null +++ b/apps/promotions/migrations/0007_plan_max_amount_plan_min_amount_and_more.py @@ -0,0 +1,28 @@ +# Generated by Django 5.2.6 on 2025-09-20 11:25 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('promotions', '0006_rename_details_event_data'), + ] + + operations = [ + migrations.AddField( + model_name='plan', + name='max_amount', + field=models.FloatField(blank=True, null=True), + ), + migrations.AddField( + model_name='plan', + name='min_amount', + field=models.FloatField(blank=True, null=True), + ), + migrations.AlterField( + model_name='plan', + name='promotion_type', + field=models.CharField(choices=[('percentage', 'percentage'), ('others', 'others')], db_index=True, max_length=64, verbose_name='promotion type'), + ), + ] diff --git a/apps/promotions/models.py b/apps/promotions/models.py index 5a3def0..8108e91 100644 --- a/apps/promotions/models.py +++ b/apps/promotions/models.py @@ -6,6 +6,7 @@ from django.utils import timezone from oauth2_provider.settings import oauth2_settings from apps.promotions.handlers import PromotionTypeChoices, BasePromotionHandler +from apps.users.models import User from utils.models import BaseModel from django.utils.translation import gettext_lazy as _ @@ -14,6 +15,7 @@ from django.utils.translation import gettext_lazy as _ class EventQuerySet(models.QuerySet): pass + class Event(BaseModel): label = models.CharField(max_length=255, db_index=True) data = models.JSONField() # from to amount application user etc @@ -25,10 +27,10 @@ class Event(BaseModel): def analyze(self): for plan in Plan.objects.get_related_to_event(self): + print(plan) plan.process_event(self) - class PlanQuerySet(models.QuerySet): # this is for list of discount code for example @@ -48,11 +50,13 @@ class Plan(BaseModel): event_list = models.JSONField(default=list) title = models.CharField(max_length=255, verbose_name=_('title'), db_index=True) description = models.TextField(verbose_name=_('description'), blank=True) - promotion_type = models.CharField(max_length=64, verbose_name=_('promotion type'), db_index=True, choices=PromotionTypeChoices.choices) + promotion_type = models.CharField(max_length=64, verbose_name=_('promotion type'), db_index=True, + choices=PromotionTypeChoices.choices) + min_amount = models.FloatField(null=True, blank=True) + max_amount = models.FloatField(null=True, blank=True) policy = models.JSONField(default=dict, verbose_name=_('policy'), null=True, blank=True) balance = models.IntegerField(verbose_name=_('balance'), default=0) - objects = PlanQuerySet.as_manager() def __str__(self): @@ -68,7 +72,7 @@ class Plan(BaseModel): def calculate_promotion(self, **kwargs): handler = self.handler - self.base_amount = kwargs.get('base_amount', 0) + # self.base_amount = kwargs.get('base_amount', 0) return handler.calculate(**kwargs) def reserve_promotion_amount(self, amount): @@ -80,14 +84,20 @@ class Plan(BaseModel): return updated def process_event(self, event=None): + print(event) referral_code = event.data.get('referral_code') user_uuid = event.data.get('user_uuid') - promotion_amount = self.calculate_promotion() - if referral_code and promotion_amount and not self.promotions.filter(user_id=referral_code, data__user_uuid=user_uuid).exists(): + promotion_amount = self.calculate_promotion(**self.policy) + if referral_code and promotion_amount and not self.promotions.filter(user_id=referral_code, + data__user_uuid=user_uuid).exists(): + referral_user, created = User.objects.get_or_create(uuid=referral_code) + user = User.objects.get_or_create(uuid=user_uuid) with transaction.atomic(): if self.reserve_promotion_amount(promotion_amount): - promotion, created = Promotion.objects.get_or_create() - if created: + promotion, created = Promotion.objects.get_or_create(plan=self, user=referral_user, defaults={ + "data": event.data + }) + if not created: raise Exception('Promotion already reserved') else: raise Exception('Promotion already reserved') @@ -139,9 +149,7 @@ class Promotion(BaseModel): raise Exception(error_message) def promote(self, **kwargs): - with transaction.atomic(): - self.plan.reserve_promotion_amount(self) - self.change_state(from_states=[Promotion.StateChoices.CREATED], to_state=Promotion.StateChoices.ASSIGNED, + self.change_state(from_states=[Promotion.StateChoices.CREATED], to_state=Promotion.StateChoices.ASSIGNED, same_ok=False, raise_exception=True) handler = self.plan.handler @@ -149,6 +157,3 @@ class Promotion(BaseModel): self.change_state(from_states=[Promotion.StateChoices.ASSIGNED], to_state=Promotion.StateChoices.PROMOTED) return True return False - - -