From 6ccbadbbdca5919a943b971959f5a1761e29eab6 Mon Sep 17 00:00:00 2001 From: Mojtaba-z Date: Sun, 3 Aug 2025 11:52:29 +0330 Subject: [PATCH] related quotas --- ...4_alter_deviceactivationcode_expires_at.py | 19 ++++++++++++ apps/product/signals.py | 24 ++++++++++----- .../web/api/v1/viewsets/product_api.py | 29 +++++++++++++++++++ apps/product/web/api/v1/viewsets/quota_api.py | 21 -------------- 4 files changed, 65 insertions(+), 28 deletions(-) create mode 100644 apps/pos_device/migrations/0024_alter_deviceactivationcode_expires_at.py diff --git a/apps/pos_device/migrations/0024_alter_deviceactivationcode_expires_at.py b/apps/pos_device/migrations/0024_alter_deviceactivationcode_expires_at.py new file mode 100644 index 0000000..68a8ed7 --- /dev/null +++ b/apps/pos_device/migrations/0024_alter_deviceactivationcode_expires_at.py @@ -0,0 +1,19 @@ +# Generated by Django 5.0 on 2025-08-03 08:21 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('pos_device', '0023_alter_deviceactivationcode_expires_at'), + ] + + operations = [ + migrations.AlterField( + model_name='deviceactivationcode', + name='expires_at', + field=models.DateTimeField(default=datetime.datetime(2025, 8, 3, 11, 51, 14, 712627)), + ), + ] diff --git a/apps/product/signals.py b/apps/product/signals.py index 03b5d31..de5fdf5 100644 --- a/apps/product/signals.py +++ b/apps/product/signals.py @@ -84,25 +84,35 @@ def update_product_stats(instance: Product, distribution: QuotaDistribution = No ) # number of quotas - quotas_count = instance.quotas.filter(is_closed=False, registerer_organization=organization) # noqa - total_quotas_weight = quotas_count.aggregate( # noqa + quota = Quota.objects.filter( + Q( + distributions_assigned__in=QuotaDistribution.objects.filter( + Q(assigned_organization=organization) | + Q(assigner_organization=organization) + ) + ) | + Q(registerer_organization=organization), + product=instance + ).distinct() + + quotas_count = quota.count() # noqa + + total_quotas_weight = quota.aggregate( # noqa total=models.Sum('quota_weight') )['total'] or 0 - quotas_count = quotas_count.count() - # total weight of product that assigned in quota - active_quotas_weight = instance.quotas.filter(is_closed=False, registerer_organization=organization).aggregate( + active_quotas_weight = quota.filter(is_closed=False).aggregate( total=models.Sum('quota_weight') )['total'] or 0 - closed_quotas_weight = instance.quotas.filter(is_closed=True, registerer_organization=organization).aggregate( # noqa + closed_quotas_weight = quota.filter(is_closed=True).aggregate( # noqa total=models.Sum('quota_weight') )['total'] or 0 # total remaining weight of product quotas - total_remaining_quotas_weight = instance.quotas.filter(is_closed=False).aggregate( # noqa + total_remaining_quotas_weight = quota.filter(is_closed=False).aggregate( # noqa total=models.Sum('remaining_weight') )['total'] or 0 diff --git a/apps/product/web/api/v1/viewsets/product_api.py b/apps/product/web/api/v1/viewsets/product_api.py index adecbb5..9c56da6 100644 --- a/apps/product/web/api/v1/viewsets/product_api.py +++ b/apps/product/web/api/v1/viewsets/product_api.py @@ -1,5 +1,6 @@ import datetime from apps.product.web.api.v1.serializers import product_serializers as product_serializers +from apps.product.web.api.v1.serializers import quota_serializers from common.helpers import get_organization_by_user from rest_framework.exceptions import APIException from apps.product import models as product_models @@ -84,6 +85,34 @@ class ProductViewSet(viewsets.ModelViewSet): serializer = self.get_serializer(queryset, many=True) return Response(serializer.data) + @action( + methods=['get'], + detail=True, + url_path='related_quotas', + url_name='related_quotas', + name='related_quotas' + ) + @transaction.atomic() + def my_related_quotas_by_product(self, request, pk=None): + """ quotas that related to my organization and product """ + + organization = get_organization_by_user(request.user) + quota = product_models.Quota.objects.filter( + Q( + distributions_assigned__in=product_models.QuotaDistribution.objects.filter( + Q(assigned_organization=organization) | + Q(assigner_organization=organization) + ) + ) | + Q(registerer_organization=organization), + product=self.get_object() + ).distinct() + + page = self.paginate_queryset(quota) + if page is not None: + serializer = quota_serializers.QuotaSerializer(page, many=True) + return self.get_paginated_response(serializer.data) + @action( methods=['put'], detail=True, diff --git a/apps/product/web/api/v1/viewsets/quota_api.py b/apps/product/web/api/v1/viewsets/quota_api.py index 83061d9..054a6f8 100644 --- a/apps/product/web/api/v1/viewsets/quota_api.py +++ b/apps/product/web/api/v1/viewsets/quota_api.py @@ -379,27 +379,6 @@ class QuotaViewSet(viewsets.ModelViewSet, DynamicSearchMixin): # noqa except Exception as e: raise APIException("none object", code=403) - @action( - methods=['get'], - detail=False, - url_path='statistics_by_product', - url_name='statistics_by_product', - name='statistics_by_product' - ) - @transaction.atomic - def quotas_statistics_by_product(self, request): - """ quota statistics of each product in organization warehouse """ - - product_data = [] - - organization = get_organization_by_user(request.user) - products = get_products_in_warehouse(organization.id) - - for product in products: - product_data.append(product.quota_information()) - - return Response(product_data, status=status.HTTP_200_OK) - @action( methods=['get'], detail=True,