From 8c9f7aca021ab10e18d0f58e3e992f4947941d10 Mon Sep 17 00:00:00 2001 From: Mojtaba-z Date: Sun, 1 Feb 2026 09:03:17 +0330 Subject: [PATCH] import --> distribute from distribution --- .../tag/services/tag_distribution_services.py | 155 +++++++++++++++++- apps/tag/signals/tag_distribution_signals.py | 135 ++++++++++++++- apps/tag/web/api/v1/api.py | 50 ++++++ 3 files changed, 334 insertions(+), 6 deletions(-) diff --git a/apps/tag/services/tag_distribution_services.py b/apps/tag/services/tag_distribution_services.py index 26ed968..9316a40 100644 --- a/apps/tag/services/tag_distribution_services.py +++ b/apps/tag/services/tag_distribution_services.py @@ -4,6 +4,7 @@ from django.db import transaction from django.db.models import Sum, Q from django.db.models.aggregates import Count from django.db.models.functions import Coalesce +from rest_framework.exceptions import PermissionDenied from apps.authentication.models import Organization from apps.livestock.models import LiveStockSpecies @@ -156,11 +157,157 @@ class TagDistributionService: return {'tag_distributions': distributions, 'distributions_batch': dist_batch} - def create_distribution_from_distribution(self, org: Organization = None, tag_batch: TagDistributionBatch = None): - pass + def create_distribution_from_distribution( + self, org: Organization = None, + tag_batch: TagDistributionBatch = None, + data: dict = None + ): + """ + create a distribution from distribution to target organization + """ + with transaction.atomic(): + distributions = [] + total_counted_tags = 0 - def edit_distribution_from_distribution(self, org: Organization = None, tag_batch: TagDistributionBatch = None): - pass + assigned_org = Organization.objects.get(id=data['assigned_org']) + parent_batch = TagDistributionBatch.objects.get( + id=data['parent_distribution_batch'] + ) + + if parent_batch.assigned_org != org: + raise PermissionDenied("دسترسی غیرمجاز") # noqa + + for dist_data in data['dists']: + species = dist_data['species_code'] + count = dist_data['count'] + parent_tag_distribution = TagDistribution.objects.get( + id=data['parent_tag_distribution'] + ) + + tags = Tag.objects.filter( + distributions__tag_distribution_batch=parent_batch, + species_code=species, + status='R', + organization=org + ) + + if tags.count() < count: + raise TagException("پلاک کافی برای این گونه وجود ندارد", 403) # noqa + + dist = TagDistribution.objects.create( + parent=parent_tag_distribution, + assigner_org=org, + assigned_org=assigned_org, + species_code=species, + total_tag_count=count, + remaining_number=count, + dist_identity=generate_unique_code( + f"{random.randint(1000, 9999)}" + ), + ) + + selected_tags = tags.order_by('create_date')[:count] + dist.tag.add(*selected_tags) + + distributions.append(dist) + total_counted_tags += count + + dist_batch = TagDistributionBatch.objects.create( + parent=parent_batch, + assigner_org=org, + assigned_org=assigned_org, + total_tag_count=total_counted_tags, + distribution_type='batch', + dist_batch_identity=generate_unique_code( + f"{random.randint(1000, 9999)}" + ) + ) + + dist_batch.distributions.add(*distributions) + + return { + 'tag_distributions': distributions, + 'distributions_batch': dist_batch + } + + def edit_distribution_from_distribution( + self, org: Organization = None, + tag_batch: TagDistributionBatch = None, + data: dict = None + + ): + with transaction.atomic(): + + if tag_batch.assigner_org != org: + raise PermissionDenied("اجازه ویرایش این توزیع را ندارید") + + for dist in tag_batch.distributions.all(): + dist.tag.all().update( + status='R', + organization=org + ) + + old_distributions = tag_batch.distributions.all() + tag_batch.distributions.clear() + old_distributions.delete() + + assigned_org = Organization.objects.get(id=data['assigned_org']) + parent_batch = tag_batch.parent + + distributions = [] + total_counted_tags = 0 + + for dist_data in data['dists']: + species = dist_data['species_code'] + count = dist_data['count'] + + tags = Tag.objects.filter( + distributions__tag_distribution_batch=parent_batch, + species_code=species, + status='R', + organization=org + ) + + if tags.count() < count: + raise TagException( + "پلاک کافی برای این گونه وجود ندارد", # noqa + 403 + ) + + dist = TagDistribution.objects.create( + parent=None, + assigner_org=org, + assigned_org=assigned_org, + species_code=species, + total_tag_count=count, + remaining_number=count, + dist_identity=generate_unique_code( + f"{random.randint(1000, 9999)}" + ), + ) + + selected_tags = tags.order_by('create_date')[:count] + dist.tag.add(*selected_tags) + + distributions.append(dist) + total_counted_tags += count + + # 5️⃣ update distribution batch + tag_batch.assigned_org = assigned_org + tag_batch.total_tag_count = total_counted_tags + tag_batch.is_closed = False + tag_batch.save(update_fields=[ + 'assigned_org', + 'total_tag_count', + 'is_closed' + ]) + + tag_batch.distributions.add(*distributions) + + return { + 'tag_distributions': distributions, + 'distributions_batch': tag_batch + } def distribution_batch_main_dashboard(self, org: Organization, is_closed: str = 'false'): """ diff --git a/apps/tag/signals/tag_distribution_signals.py b/apps/tag/signals/tag_distribution_signals.py index e44c7cf..6e8fe8e 100644 --- a/apps/tag/signals/tag_distribution_signals.py +++ b/apps/tag/signals/tag_distribution_signals.py @@ -1,8 +1,10 @@ -from django.db.models.aggregates import Count +from django.db import transaction +from django.db.models import Count +from django.db.models.signals import m2m_changed from django.db.models.signals import post_save from django.dispatch import receiver -from apps.tag.models import TagDistribution, TagDistributionBatch +from apps.tag.models import TagDistribution, TagDistributionBatch, Tag @receiver(post_save, sender=TagDistribution) @@ -41,3 +43,132 @@ def calculate_tag_distribution_detail(sender, instance: TagDistributionBatch, ** print(tag_dist_batch.remaining_tag_count) instance.flag = True tag_dist_batch.save(update_fields=['remaining_tag_count']) + +# @receiver(m2m_changed, sender=TagDistribution.tag.through) +# def on_tags_added_to_distribution(sender, instance, action, pk_set, **kwargs): +# if action != 'post_add': +# return +# +# if not pk_set: +# return +# +# with transaction.atomic(): +# +# Tag.objects.filter( +# id__in=pk_set +# ).update( +# status='R', +# organization=instance.assigned_org +# ) +# +# total = instance.tag.count() +# +# instance.total_tag_count = total +# instance.distributed_number = total +# instance.remaining_number = 0 +# instance.save(update_fields=[ +# 'total_tag_count', +# 'distributed_number', +# 'remaining_number' +# ]) +# +# if instance.batch: +# batch = instance.batch +# +# distributed_tags = Tag.objects.filter( +# batches=batch, +# status__in=['R', 'A'] +# ).count() +# +# total_tags = batch.tag.count() +# +# batch.total_distributed_tags = distributed_tags +# batch.total_remaining_tags = total_tags - distributed_tags +# batch.status = ( +# 'distributed' +# if batch.total_remaining_tags == 0 +# else 'created' +# ) +# +# batch.save(update_fields=[ +# 'total_distributed_tags', +# 'total_remaining_tags', +# 'status' +# ]) +# +# for dist_batch in instance.tag_distribution_batch.all(): +# agg = dist_batch.distributions.aggregate( +# total=Count('tag') +# ) +# +# total_dist = agg.get('total', 0) +# +# dist_batch.total_distributed_tag_count = total_dist +# dist_batch.remaining_tag_count = ( +# dist_batch.total_tag_count - total_dist +# ) +# dist_batch.is_closed = dist_batch.remaining_tag_count == 0 +# +# dist_batch.save(update_fields=[ +# 'total_distributed_tag_count', +# 'remaining_tag_count', +# 'is_closed' +# ]) +# +# +# @receiver(m2m_changed, sender=TagDistribution.tag.through) +# def on_tags_removed_from_distribution(sender, instance, action, pk_set, **kwargs): +# if action not in ['post_remove', 'post_clear']: +# return +# +# if action == 'post_clear': +# pk_set = list(instance.tag.values_list('id', flat=True)) +# +# if not pk_set: +# return +# +# with transaction.atomic(): +# +# Tag.objects.filter(id__in=pk_set).update( +# status='R', +# organization=instance.assigner_org +# ) +# +# total = instance.tag.count() +# instance.total_tag_count = total +# instance.distributed_number = total +# instance.remaining_number = 0 +# instance.save(update_fields=[ +# 'total_tag_count', +# 'distributed_number', +# 'remaining_number' +# ]) +# +# if instance.batch: +# batch = instance.batch +# distributed_tags = Tag.objects.filter( +# batches=batch, +# status__in=['R', 'A'] +# ).count() +# total_tags = batch.tag.count() +# batch.total_distributed_tags = distributed_tags +# batch.total_remaining_tags = total_tags - distributed_tags +# batch.status = 'distributed' if batch.total_remaining_tags == 0 else 'created' +# batch.save(update_fields=[ +# 'total_distributed_tags', +# 'total_remaining_tags', +# 'status' +# ]) +# +# for dist_batch in instance.tag_distribution_batch.all(): +# total_dist = dist_batch.distributions.aggregate( +# total=Count('tag') +# ).get('total', 0) +# dist_batch.total_distributed_tag_count = total_dist +# dist_batch.remaining_tag_count = dist_batch.total_tag_count - total_dist +# dist_batch.is_closed = dist_batch.remaining_tag_count == 0 +# dist_batch.save(update_fields=[ +# 'total_distributed_tag_count', +# 'remaining_tag_count', +# 'is_closed' +# ]) diff --git a/apps/tag/web/api/v1/api.py b/apps/tag/web/api/v1/api.py index 933d666..3dc238b 100644 --- a/apps/tag/web/api/v1/api.py +++ b/apps/tag/web/api/v1/api.py @@ -450,6 +450,56 @@ class TagDistributionViewSet( serializer = self.serializer_class(distribution_data.get('tag_distributions'), many=True) return Response(serializer.data, status=status.HTTP_200_OK) + @action( + methods=['post'], + detail=True, + url_path='distribute_distribution', + url_name='distribute_distribution', + name='distribute_distribution', + ) + def create_distribute_from_distribution(self, request, pk=None): + """ + distribute from a tag distribution + """ + + data = request.data.copy() + org = get_organization_by_user(request.user) + dist_batch = tag_models.TagDistributionBatch.objects.get(id=pk) + + distribution_data = self.create_distribution_from_distribution( + org=org, + tag_batch=dist_batch, + data=data + ) + + serializer = self.serializer_class(distribution_data.get('tag_distributions'), many=True) + return Response(serializer.data, status=status.HTTP_200_OK) + + @action( + methods=['put'], + detail=True, + url_path='distribute_distribution', + url_name='distribute_distribution', + name='distribute_distribution', + ) + def update_distribute_from_distribution(self, request, pk=None): + """ + update created distribution from distribution + """ + + data = request.data.copy() + org = get_organization_by_user(request.user) + dist_batch = tag_models.TagDistributionBatch.objects.get(id=pk) + + distribution_data = self.edit_distribution_from_distribution( + org=org, + tag_batch=dist_batch, + data=data + ) + + serializer = self.serializer_class(distribution_data.get('tag_distributions'), many=True) + return Response(serializer.data, status=status.HTTP_200_OK) + @action( methods=['get'], detail=True,