From 6816c92661fc3c7d27ee708d1e787a46708a10ec Mon Sep 17 00:00:00 2001 From: Mojtaba-z Date: Mon, 8 Dec 2025 08:38:02 +0330 Subject: [PATCH] import - first impression of quota dashboard by product --- .../services/quota_dashboard_service.py | 27 +- apps/product/signals.py | 294 +++++++++--------- .../validators/quota_stats_validator.py | 1 - 3 files changed, 171 insertions(+), 151 deletions(-) diff --git a/apps/product/services/quota_dashboard_service.py b/apps/product/services/quota_dashboard_service.py index 3ceee1d..2f038b6 100644 --- a/apps/product/services/quota_dashboard_service.py +++ b/apps/product/services/quota_dashboard_service.py @@ -1,4 +1,5 @@ -from django.db.models import Sum, Count +from django.db import models +from django.db.models import Sum, Count, Q from django.db.models.functions import Coalesce from apps.authentication.models import Organization @@ -48,3 +49,27 @@ class QuotaDashboardService: return { "quotas_summary": org_quota_stats, } + + @staticmethod + def get_dashboard_by_product(self, organization: Organization, products: list[int]): + + stat_by_prod = [] + for prod in products: + org_quota_stat = OrganizationQuotaStats.objects.filter( + organization=organization, + quota__product_id=prod + ) + product_stat_data = org_quota_stat.aggregate( + quotas_count=Count('id'), + total_quotas_weight=models.Sum('total_amount'), + active_quotas_weight=models.Sum('active_quotas_weight', filter=Q(quota__is_closed=False)), + closed_quotas_weight=models.Sum('closed_quotas_weight', filter=Q(quota__is_closed=True)), + total_remaining_quotas_weight=models.Sum('remaining_amount'), + total_distributed=models.Sum('quota_distributed'), + total_warehouse_entry=models.Sum('inventory_received'), + total_sold=models.Sum('total_sold'), + ) + + stat_by_prod.append(product_stat_data) + + return stat_by_prod diff --git a/apps/product/signals.py b/apps/product/signals.py index 2b09839..300ea84 100644 --- a/apps/product/signals.py +++ b/apps/product/signals.py @@ -1,7 +1,5 @@ -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 import Sum from django.db.models.signals import post_save, post_delete, post_init from django.dispatch import receiver @@ -10,11 +8,9 @@ from apps.warehouse.models import ( InventoryQuotaSaleTransaction, InventoryEntry ) -from common.helpers import get_organization_by_user from .models import ( QuotaDistribution, Quota, - ProductStats, QuotaStats, OrganizationQuotaStats ) from .services.quota_stat_service import QuotaStatsService @@ -74,150 +70,150 @@ def update_quota_remaining(sender, instance, **kwargs): remaining_distribution_weight(instance) -def update_product_stats(instance: OrganizationQuotaStats): - """ update all stats of product """ - - user = get_current_user() # get user object - if not isinstance(user, AnonymousUser): - organization = get_organization_by_user(user) - # QuotaStatsValidator.validate_assigner_has_enough( - # organization, - # distribution.quota, - # distribution.weight, - # allow_zero=True - # ) - - stat, created = ProductStats.objects.get_or_create( - organization=organization, - product=instance, - sale_unit=instance.quota.sale_unit.unit - ) - - # number of quotas - - org_quota_stat = OrganizationQuotaStats.objects.filter( - organization=organization, - quota__product=instance.quota.product, - ) - - quotas_count = org_quota_stat.count() # noqa - - product_stat_data = org_quota_stat.aggregate( - total_quotas_weight=models.Sum('total_amount'), - active_quotas_weight=models.Sum('active_quotas_weight', filter=Q(quota__is_closed=False)), - closed_quotas_weight=models.Sum('closed_quotas_weight', filter=Q(quota__is_closed=True)), - total_remaining_quotas_weight=models.Sum('remaining_amount'), - total_distributed=models.Sum('quota_distributed'), - total_inventory_in=models.Sum('total_inventory_in'), - total_sold=models.Sum('total_sold'), - ) - # quota = Quota.objects.filter( - # Q( - # distributions_assigned__in=QuotaDistribution.objects.filter( - # Q(assigned_organization=organization) | - # Q(assigner_organization=organization) & - # Q(parent_distribution__isnull=True) - # - # ) - # ) | - # 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 - # - # # total weight of product that assigned in quota - # active_quotas_weight = quota.filter(is_closed=False).aggregate( - # total=models.Sum('quota_weight') - # )['total'] or 0 - # - # 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 = quota.filter(is_closed=False).aggregate( # noqa - # total=models.Sum('remaining_weight') - # )['total'] or 0 - # - # received_distribution_weight = QuotaDistribution.objects.filter( - # quota__product_id=instance.id, - # quota__is_closed=False, - # quota__sale_unit=distribution.quota.sale_unit, - # assigned_organization=organization, - # parent_distribution__isnull=True - # ) - # - # received_distribution_number = received_distribution_weight.count() - # - # received_distribution_weight = received_distribution_weight.aggregate( - # total_weight=models.Sum('weight') - # )['total_weight'] or 0 - # - # # product total distributed weight from quota - # given_distribution_weight = QuotaDistribution.objects.filter( - # quota__product_id=instance.id, - # quota__is_closed=False, - # quota__sale_unit=distribution.quota.sale_unit, - # assigner_organization=organization, - # parent_distribution__isnull=True - # ) - # - # given_distribution_number = given_distribution_weight.count() - # given_distribution_weight = given_distribution_weight.aggregate( - # total_weight=models.Sum('weight') - # )['total_weight'] or 0 - # - # if received_distribution_weight > 0: - # distribution_weight_balance = received_distribution_weight - given_distribution_weight - # else: - # distribution_weight_balance = given_distribution_weight - # - # # total sold of product from quota - # total_sold = QuotaDistribution.objects.filter( - # quota__product_id=instance.id, - # quota__is_closed=False, - # quota__sale_unit=distribution.quota.sale_unit, - # assigned_organization=organization - # ).aggregate(total_sold=models.Sum('been_sold'))['total_sold'] or 0 - # - # # total entry from product to inventory - # total_warehouse_entry = QuotaDistribution.objects.filter( - # quota__product_id=instance.id, - # quota__is_closed=False, - # quota__sale_unit=distribution.quota.sale_unit, - # assigned_organization=organization - # ).aggregate(total_entry=models.Sum('warehouse_entry'))['total_entry'] or 0 - - # stat.quotas_number = quotas_count - # stat.active_quotas_weight = active_quotas_weight - # stat.closed_quotas_weight = closed_quotas_weight - # stat.total_quota_weight = total_quotas_weight - # stat.total_quota_remaining = total_remaining_quotas_weight - # stat.total_remaining_distribution_weight = distribution_weight_balance - # stat.received_distribution_weight = received_distribution_weight - # stat.given_distribution_weight = given_distribution_weight - # stat.received_distribution_number = received_distribution_number - # stat.given_distribution_number = given_distribution_number - # stat.total_warehouse_entry = total_warehouse_entry - # stat.total_sold = total_sold - # stat.save(update_fields=[ - # "quotas_number", - # "active_quotas_weight", - # "closed_quotas_weight", - # "total_quota_weight", - # "total_quota_remaining", - # "total_remaining_distribution_weight", - # "received_distribution_weight", - # "given_distribution_weight", - # "received_distribution_number", - # "total_warehouse_entry", - # "total_sold", - # ]) +# def update_product_stats(instance: OrganizationQuotaStats): +# """ update all stats of product """ +# +# user = get_current_user() # get user object +# if not isinstance(user, AnonymousUser): +# organization = get_organization_by_user(user) +# # QuotaStatsValidator.validate_assigner_has_enough( +# # organization, +# # distribution.quota, +# # distribution.weight, +# # allow_zero=True +# # ) +# +# stat, created = ProductStats.objects.get_or_create( +# organization=organization, +# product=instance, +# sale_unit=instance.quota.sale_unit.unit +# ) +# +# # number of quotas +# +# org_quota_stat = OrganizationQuotaStats.objects.filter( +# organization=organization, +# quota__product=instance.quota.product, +# ) +# +# quotas_count = org_quota_stat.count() # noqa +# +# product_stat_data = org_quota_stat.aggregate( +# total_quotas_weight=models.Sum('total_amount'), +# active_quotas_weight=models.Sum('active_quotas_weight', filter=Q(quota__is_closed=False)), +# closed_quotas_weight=models.Sum('closed_quotas_weight', filter=Q(quota__is_closed=True)), +# total_remaining_quotas_weight=models.Sum('remaining_amount'), +# total_distributed=models.Sum('quota_distributed'), +# total_warehouse_entry=models.Sum('inventory_received'), +# total_sold=models.Sum('total_sold'), +# ) +# # quota = Quota.objects.filter( +# # Q( +# # distributions_assigned__in=QuotaDistribution.objects.filter( +# # Q(assigned_organization=organization) | +# # Q(assigner_organization=organization) & +# # Q(parent_distribution__isnull=True) +# # +# # ) +# # ) | +# # 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 +# # +# # # total weight of product that assigned in quota +# # active_quotas_weight = quota.filter(is_closed=False).aggregate( +# # total=models.Sum('quota_weight') +# # )['total'] or 0 +# # +# # 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 = quota.filter(is_closed=False).aggregate( # noqa +# # total=models.Sum('remaining_weight') +# # )['total'] or 0 +# # +# # received_distribution_weight = QuotaDistribution.objects.filter( +# # quota__product_id=instance.id, +# # quota__is_closed=False, +# # quota__sale_unit=distribution.quota.sale_unit, +# # assigned_organization=organization, +# # parent_distribution__isnull=True +# # ) +# # +# # received_distribution_number = received_distribution_weight.count() +# # +# # received_distribution_weight = received_distribution_weight.aggregate( +# # total_weight=models.Sum('weight') +# # )['total_weight'] or 0 +# # +# # # product total distributed weight from quota +# # given_distribution_weight = QuotaDistribution.objects.filter( +# # quota__product_id=instance.id, +# # quota__is_closed=False, +# # quota__sale_unit=distribution.quota.sale_unit, +# # assigner_organization=organization, +# # parent_distribution__isnull=True +# # ) +# # +# # given_distribution_number = given_distribution_weight.count() +# # given_distribution_weight = given_distribution_weight.aggregate( +# # total_weight=models.Sum('weight') +# # )['total_weight'] or 0 +# # +# # if received_distribution_weight > 0: +# # distribution_weight_balance = received_distribution_weight - given_distribution_weight +# # else: +# # distribution_weight_balance = given_distribution_weight +# # +# # # total sold of product from quota +# # total_sold = QuotaDistribution.objects.filter( +# # quota__product_id=instance.id, +# # quota__is_closed=False, +# # quota__sale_unit=distribution.quota.sale_unit, +# # assigned_organization=organization +# # ).aggregate(total_sold=models.Sum('been_sold'))['total_sold'] or 0 +# # +# # # total entry from product to inventory +# # total_warehouse_entry = QuotaDistribution.objects.filter( +# # quota__product_id=instance.id, +# # quota__is_closed=False, +# # quota__sale_unit=distribution.quota.sale_unit, +# # assigned_organization=organization +# # ).aggregate(total_entry=models.Sum('warehouse_entry'))['total_entry'] or 0 +# +# # stat.quotas_number = quotas_count +# # stat.active_quotas_weight = active_quotas_weight +# # stat.closed_quotas_weight = closed_quotas_weight +# # stat.total_quota_weight = total_quotas_weight +# # stat.total_quota_remaining = total_remaining_quotas_weight +# # stat.total_remaining_distribution_weight = distribution_weight_balance +# # stat.received_distribution_weight = received_distribution_weight +# # stat.given_distribution_weight = given_distribution_weight +# # stat.received_distribution_number = received_distribution_number +# # stat.given_distribution_number = given_distribution_number +# # stat.total_warehouse_entry = total_warehouse_entry +# # stat.total_sold = total_sold +# # stat.save(update_fields=[ +# # "quotas_number", +# # "active_quotas_weight", +# # "closed_quotas_weight", +# # "total_quota_weight", +# # "total_quota_remaining", +# # "total_remaining_distribution_weight", +# # "received_distribution_weight", +# # "given_distribution_weight", +# # "received_distribution_number", +# # "total_warehouse_entry", +# # "total_sold", +# # ]) def update_quota_stats(instance: Quota): diff --git a/apps/product/validators/quota_stats_validator.py b/apps/product/validators/quota_stats_validator.py index a95bc33..6c80360 100644 --- a/apps/product/validators/quota_stats_validator.py +++ b/apps/product/validators/quota_stats_validator.py @@ -79,7 +79,6 @@ class QuotaStatsValidator: @staticmethod def validate_distribution_delete(distribution): - # اگر already sold (been_sold > 0) نباید حذف شود been_sold = getattr(distribution, "been_sold", None) if been_sold and been_sold > 0: raise ValidationError("Cannot delete distribution: it has sold items.")