diff --git a/apps/product/services/quota_stat_service.py b/apps/product/services/quota_stat_service.py new file mode 100644 index 0000000..a394eed --- /dev/null +++ b/apps/product/services/quota_stat_service.py @@ -0,0 +1,86 @@ +from apps.product.models import QuotaDistribution, OrganizationQuotaStats + + +class QuotaStatsService: + @staticmethod + def apply_distribution(distribution: QuotaDistribution): + quota = distribution.quota + + # origin org + assigner = distribution.assigner_organization + # destination org + assigned = distribution.assigned_organization + print(assigned) + # ================ origin ================ + assigner_stat, _ = OrganizationQuotaStats.objects.get_or_create( + organization=assigner, + quota=quota + ) + + assigner_stat.remaining_amount -= distribution.weight + assigner_stat.total_distributed += distribution.weight + assigner_stat.save() + + # ============== destination ================ + assigned_stat, _ = OrganizationQuotaStats.objects.get_or_create( + organization=assigned, + quota=quota + ) + + assigned_stat.total_amount += distribution.weight + assigned_stat.remaining_amount += distribution.weight + assigned_stat.distributions.add(distribution) + assigned_stat.save() + + @staticmethod + def update_distribution(distribution: QuotaDistribution, old_weight: int): + diff = distribution.weight - old_weight + if diff == 0: + return + + quota = distribution.quota + + assigner = distribution.assigner_organization + assigned = distribution.assigned_organization + + assigner_stat = OrganizationQuotaStats.objects.get( + organization=assigner, + quota=quota + ) + assigned_stat = OrganizationQuotaStats.objects.get( + organization=assigned, + quota=quota + ) + # if diff > 0 it is added to destination + assigner_stat.remaining_amount -= diff + assigner_stat.total_distributed += diff + assigner_stat.save() + + assigned_stat.total_amount += diff + assigned_stat.remaining_amount += diff + print(assigned_stat.id) + + assigned_stat.save() + + @staticmethod + def delete_distribution(distribution: QuotaDistribution): + quota = distribution.quota + + # origin + assigner_stat = OrganizationQuotaStats.objects.get( + organization=distribution.assigner_organization, + quota=quota + ) + assigner_stat.remaining_amount += distribution.weight + assigner_stat.total_distributed -= distribution.weight + assigner_stat.save() + + # destination + assigned_stat = OrganizationQuotaStats.objects.get( + organization=distribution.assigned_organization, + quota=quota + ) + assigned_stat.total_amount -= distribution.weight + assigned_stat.remaining_amount -= distribution.weight + assigned_stat.distributions.remove(distribution) + assigned_stat.save() diff --git a/apps/product/signals.py b/apps/product/signals.py index 98904fd..5b8872d 100644 --- a/apps/product/signals.py +++ b/apps/product/signals.py @@ -2,7 +2,7 @@ from crum import get_current_user from django.contrib.auth.models import AnonymousUser from django.db import models from django.db.models import Sum, Q -from django.db.models.signals import post_save, post_delete +from django.db.models.signals import post_save, post_delete, post_init from django.dispatch import receiver from apps.warehouse.models import ( @@ -12,12 +12,12 @@ from apps.warehouse.models import ( from common.helpers import get_organization_by_user from .models import ( QuotaDistribution, - OrganizationQuotaStats, Quota, Product, ProductStats, - QuotaStats + QuotaStats, OrganizationQuotaStats ) +from .services.quota_stat_service import QuotaStatsService def recalculate_remaining_amount(quota): @@ -255,6 +255,48 @@ def update_stats_on_change(sender, instance, **kwargs): return +@receiver(post_init, sender=QuotaDistribution) +def store_original_weight(sender, instance, **kwargs): + pass + + +@receiver(post_init, sender=QuotaDistribution) +def distribution_pre_save(sender, instance, **kwargs): + if instance.pk: + instance._is_update = True + instance._old_weight = instance.weight + else: + instance._is_update = False + + +@receiver(post_save, sender=QuotaDistribution) +def update_stats_after_save(sender, instance, created, **kwargs): + if getattr(instance, 'stat_from_signal', False): + return + + if instance.trash: + return + + if not instance._is_update: # noqa + QuotaStatsService.apply_distribution(instance) + + else: + QuotaStatsService.update_distribution(instance, instance._old_weight) # noqa + + instance.stat_from_signal = True + + +@receiver(post_save, sender=QuotaDistribution) +def delete_stats_after_soft_delete(sender, instance, **kwargs): + if getattr(instance, 'stat_from_signal', False): + return + + if instance.trash: + QuotaStatsService.delete_distribution(instance) + + instance.stat_from_signal = True + + @receiver(post_save, sender=Quota) def organization_quota_stats(sender, instance: Quota, created: bool, **kwargs): """ @@ -285,45 +327,45 @@ def organization_quota_stats(sender, instance: Quota, created: bool, **kwargs): # prevent from maximum recursion loop instance.stat_from_signal = True - - -@receiver(post_save, sender=QuotaDistribution) -def update_quota_stats_on_distribution(sender, instance: QuotaDistribution, created, **kwargs): - if getattr(instance, 'one_time_loop_flag', False): - return - - if instance.trash: - return - - org = instance.assigned_organization - quota = instance.quota - - stats, _ = OrganizationQuotaStats.objects.get_or_create( - quota=quota, - organization=org, - ) - stats.distributions.add(instance) - stats.update_amount(main_quota=True) - instance.one_time_loop_flag = True - - -@receiver(post_save, sender=QuotaDistribution) -def handle_quota_stats_soft_delete_on_distribution(sender, instance: QuotaDistribution, created, **kwargs): - if getattr(instance, 'one_time_loop_flag', False): - return - - if instance.trash: - org = instance.assigned_organization - quota = instance.quota - - stats_qs = OrganizationQuotaStats.objects.filter( - quota=quota, - organization=org, - ) - - if stats_qs: - for stats in stats_qs: - stats.distributions.remove(instance) - stats.update_amount(main_quota=True) - - instance.one_time_loop_flag = True +# +# +# @receiver(post_save, sender=QuotaDistribution) +# def update_quota_stats_on_distribution(sender, instance: QuotaDistribution, created, **kwargs): +# if getattr(instance, 'one_time_loop_flag', False): +# return +# +# if instance.trash: +# return +# +# org = instance.assigned_organization +# quota = instance.quota +# +# stats, _ = OrganizationQuotaStats.objects.get_or_create( +# quota=quota, +# organization=org, +# ) +# stats.distributions.add(instance) +# stats.update_amount(main_quota=True) +# instance.one_time_loop_flag = True +# +# +# @receiver(post_save, sender=QuotaDistribution) +# def handle_quota_stats_soft_delete_on_distribution(sender, instance: QuotaDistribution, created, **kwargs): +# if getattr(instance, 'one_time_loop_flag', False): +# return +# +# if instance.trash: +# org = instance.assigned_organization +# quota = instance.quota +# +# stats_qs = OrganizationQuotaStats.objects.filter( +# quota=quota, +# organization=org, +# ) +# +# if stats_qs: +# for stats in stats_qs: +# stats.distributions.remove(instance) +# stats.update_amount(main_quota=True) +# +# instance.one_time_loop_flag = True