get promotion amount from another promotion
This commit is contained in:
parent
7038ada31e
commit
30ccca8efc
3 changed files with 116 additions and 10 deletions
|
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 5.2.4 on 2026-06-25 06:55
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('promotions', '0007_alter_event_options_plan_banner_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='plan',
|
||||
name='balance_holder',
|
||||
field=models.UUIDField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='plan',
|
||||
name='description_details',
|
||||
field=models.JSONField(blank=True, default=dict, verbose_name='description details'),
|
||||
),
|
||||
]
|
||||
|
|
@ -112,6 +112,8 @@ class Plan(BaseModel):
|
|||
processor = models.CharField(max_length=64, verbose_name=_('processor'), db_index=True,
|
||||
choices=ProcessorTypeChoices.choices) # TODO: processor type
|
||||
data = models.JSONField(default=dict, verbose_name=_('data'), null=True, blank=True)
|
||||
|
||||
balance_holder = models.UUIDField(null=True, blank=True)
|
||||
balance = models.IntegerField(verbose_name=_('balance'), default=0)
|
||||
|
||||
objects = PlanQuerySet.as_manager()
|
||||
|
|
@ -142,11 +144,27 @@ class Plan(BaseModel):
|
|||
yield recipient.promote(plan=self, event=event)
|
||||
|
||||
def reserve_promotion_amount(self, amount):
|
||||
|
||||
if self.balance_holder:
|
||||
balance_holder_object = Promotion.objects.get(pk=self.balance_holder)
|
||||
balance_field_name = 'promotion_amount'
|
||||
else:
|
||||
balance_holder_object = self
|
||||
balance_field_name = 'balance'
|
||||
|
||||
updated = False
|
||||
if amount and self.balance >= amount:
|
||||
updated = Plan.objects.filter(pk=self.pk, balance__gte=amount).update(
|
||||
balance=F('balance') - amount
|
||||
)
|
||||
|
||||
select_query_kwargs = {
|
||||
"pk": balance_holder_object.pk,
|
||||
f"{balance_field_name}__gte": amount
|
||||
}
|
||||
update_query_kwargs = {
|
||||
balance_field_name: F(balance_field_name) - amount
|
||||
}
|
||||
|
||||
if amount and getattr(balance_holder_object, balance_field_name) >= amount:
|
||||
updated = balance_holder_object._meta.model.objects.filter(**select_query_kwargs).update(
|
||||
**update_query_kwargs)
|
||||
return updated
|
||||
|
||||
|
||||
|
|
@ -200,7 +218,6 @@ class Recipient(BaseModel):
|
|||
if obj_value != value:
|
||||
return None
|
||||
|
||||
|
||||
model_name, key = recipient_candidate.split(':')
|
||||
if model_name == 'event':
|
||||
obj = event
|
||||
|
|
@ -277,7 +294,6 @@ class Recipient(BaseModel):
|
|||
else:
|
||||
return base_amount, promotion_amount
|
||||
|
||||
|
||||
# @property
|
||||
# def handler(self) -> BasePromotionHandler:
|
||||
# return PromotionTypeChoices(self.promotion_type).handler(self)
|
||||
|
|
@ -287,7 +303,6 @@ class Recipient(BaseModel):
|
|||
if not recipient:
|
||||
return None
|
||||
|
||||
|
||||
base_amount, promotion_amount = self.get_promotion_amount(plan=plan, event=event)
|
||||
promotion, created = Promotion.objects.get_or_create(
|
||||
promotion_amount=promotion_amount,
|
||||
|
|
@ -306,7 +321,8 @@ class Recipient(BaseModel):
|
|||
else:
|
||||
raise Exception('promotion reward not reserved')
|
||||
except Exception as e:
|
||||
promotion.change_state(from_states=[promotion.state], to_state=PaymentStateChoices.EXPECTED_FAILURE, same_ok=True)
|
||||
promotion.change_state(from_states=[promotion.state], to_state=PaymentStateChoices.EXPECTED_FAILURE,
|
||||
same_ok=True)
|
||||
promotion.refresh_from_db()
|
||||
|
||||
return promotion
|
||||
|
|
@ -382,7 +398,7 @@ class Promotion(BaseModel):
|
|||
if self.state not in [PaymentStateChoices.CREATED]:
|
||||
raise Exception(_('Cannot promote. not in correct state'))
|
||||
|
||||
if not self.promotion_amount:
|
||||
if not self.promotion_amount or self.plan.balance_holder:
|
||||
to_not_payed = self.change_state(
|
||||
from_states=[PaymentStateChoices.CREATED],
|
||||
to_state=PaymentStateChoices.SUCCESS,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ from rest_framework.test import APITestCase, override_settings, APIClient
|
|||
|
||||
from apps.promotions.tasks import analyze_event_task
|
||||
from apps.users.models import User
|
||||
from apps.promotions.models import Plan, Promotion, EventSaver, ProcessorTypeChoices, Event, Recipient
|
||||
from apps.promotions.models import Plan, Promotion, EventSaver, ProcessorTypeChoices, Event, Recipient, \
|
||||
PaymentStateChoices
|
||||
|
||||
AccessToken = get_access_token_model()
|
||||
Application = get_application_model()
|
||||
|
|
@ -465,3 +466,69 @@ class ApplicationApiFlowsTests(APITestCase):
|
|||
|
||||
self.assertEqual(self.serial_promotion_plan.balance, 100000)
|
||||
self.assertEqual(Event.objects.count(), 3)
|
||||
|
||||
def test_plan_balance_from_another_promotion_success(self):
|
||||
base_plan, _created = Plan.objects.get_or_create(
|
||||
title='base_plan',
|
||||
balance=0,
|
||||
user=self.user_1,
|
||||
application=self.application,
|
||||
event_list=['advertising:manual']
|
||||
)
|
||||
|
||||
base_promotion, _created = Promotion.objects.get_or_create(
|
||||
user_uuid = self.user_1_uuid,
|
||||
application = self.application,
|
||||
plan = base_plan,
|
||||
state = PaymentStateChoices.SUCCESS,
|
||||
base_amount = 10000,
|
||||
promotion_amount = 10000
|
||||
)
|
||||
|
||||
promotion_event_saver, _created = EventSaver.objects.get_or_create(
|
||||
title=self.first_ad_view_reward_label,
|
||||
event_label=self.first_ad_view_reward_label,
|
||||
save_once=True,
|
||||
)
|
||||
promotion_plan, _created = Plan.objects.get_or_create(
|
||||
title='promotion_plan',
|
||||
balance=0,
|
||||
balance_holder=base_promotion.pk,
|
||||
user=self.user_1,
|
||||
application=self.application,
|
||||
event_list=[self.first_ad_view_reward_label]
|
||||
)
|
||||
|
||||
self.promotion_recipient, _created = Recipient.objects.get_or_create(
|
||||
label='promotion_recipient',
|
||||
plan=promotion_plan,
|
||||
wallet_uuid=self.user_1_uuid,
|
||||
recipient_uuid_field=self.user_2_uuid,
|
||||
base_amount_field=1000,
|
||||
data={}
|
||||
|
||||
)
|
||||
|
||||
auth = self._create_authorization_header(self.user_access_token.token)
|
||||
|
||||
create_data = {
|
||||
'label': self.first_ad_view_reward_label,
|
||||
"data": {
|
||||
'user': self.user_1_uuid,
|
||||
}
|
||||
}
|
||||
|
||||
self.assertEqual(Event.objects.count(), 0)
|
||||
response = self.client.post(reverse('promotions:promotion-create', kwargs={'plan': str(promotion_plan.uuid)}),
|
||||
create_data,
|
||||
HTTP_AUTHORIZATION=auth, format='json')
|
||||
print(response.json())
|
||||
promotion_plan.refresh_from_db()
|
||||
base_promotion.refresh_from_db()
|
||||
self.assertEqual(base_promotion.base_amount, 10000)
|
||||
self.assertEqual(base_promotion.promotion_amount, 9000)
|
||||
self.assertEqual(Event.objects.count(), 1)
|
||||
|
||||
response = self.client.post(reverse('promotions:promotion-create', kwargs={'plan': str(promotion_plan.uuid)}), create_data,
|
||||
HTTP_AUTHORIZATION=auth, format='json')
|
||||
print(response.json())
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue