from django.db.models import Sum from django.db.models.signals import post_save, post_delete from common.helpers import get_organization_by_user from django.dispatch import receiver from .models import ( QuotaDistribution, Quota, Product, ProductStats, QuotaStats ) from apps.warehouse.models import ( InventoryQuotaSaleTransaction, InventoryEntry ) from django.db import models from crum import get_current_user def recalculate_remaining_amount(quota): total_distributed = quota.distributions_assigned.aggregate( total=Sum('weight') )['total'] or 0 quota.remaining_weight = quota.quota_weight - total_distributed quota.quota_distributed = total_distributed quota.save(update_fields=["remaining_weight", "quota_distributed"]) @receiver(post_save, sender=QuotaDistribution) @receiver(post_delete, sender=QuotaDistribution) def update_quota_remaining(sender, instance, **kwargs): recalculate_remaining_amount(instance.quota) def update_product_stats(instance: Product): """ update all stats of product """ organization = get_organization_by_user(get_current_user()) if ProductStats.objects.filter(organization=organization, product=instance): stat = instance.stats.get(organization=organization, product=instance) else: stat = ProductStats.objects.create(product=instance, organization=organization) # number of quotas quotas_count = instance.quotas.filter(is_closed=False).count() # noqa # total weight of product that assigned in quota active_quotas_weight = instance.quotas.filter(is_closed=False).aggregate( total=models.Sum('quota_weight') )['total'] or 0 closed_quotas_weight = instance.quotas.filter(is_closed=True).aggregate( # noqa total=models.Sum('quota_weight') )['total'] or 0 total_quotas_weight = instance.quotas.all().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=models.Sum('remaining_weight') )['total'] or 0 # product total distributed weight from quota total_distributed_weight = QuotaDistribution.objects.filter( quota__product_id=instance.id, quota__is_closed=False ).aggregate(total_weight=models.Sum('weight'))['total_weight'] or 0 # total sold of product from quota total_sold = QuotaDistribution.objects.filter( quota__product_id=instance.id, quota__is_closed=False ).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 ).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_remaining = total_remaining_quotas_weight stat.total_distributed_weight = total_distributed_weight 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_remaining", "total_distributed_weight", "total_warehouse_entry", "total_sold", ]) def update_quota_stats(instance: Quota): """ update all stats of quota """ if hasattr(instance, 'stats'): stat = instance.stats else: stat = QuotaStats.objects.create(quota=instance) total_distributed = instance.quota_distributed total_remaining = instance.remaining_weight # total entry to inventory from quota total_inventory = InventoryEntry.objects.filter( distribution__quota=instance ).aggregate( total_inventory=models.Sum('weight') )['total_inventory'] or 0 # total sale of distributions from quota total_sale = instance.distributions_assigned.filter( quota__is_closed=False ).aggregate(total_sale=models.Sum('been_sold'))['total_sale'] or 0 stat.total_distributed = total_distributed stat.remaining = total_remaining stat.total_inventory = total_inventory stat.total_sale = total_sale stat.save(update_fields=[ "total_distributed", "remaining", "total_inventory", "total_sale", ]) @receiver([post_save, post_delete], sender=QuotaDistribution) @receiver([post_save, post_delete], sender=InventoryQuotaSaleTransaction) def update_stats_on_change(sender, instance, **kwargs): if sender == QuotaDistribution: update_product_stats(instance.quota.product) update_quota_stats(instance.quota) elif sender == InventoryQuotaSaleTransaction: update_product_stats(instance.quota_distribution.quota.product) update_quota_stats(instance.quota_distribution.quota)