From 2e3ddd25599258d45a8e0a8b44518340095b86a4 Mon Sep 17 00:00:00 2001 From: Mojtaba-z Date: Sat, 2 Aug 2025 14:34:24 +0330 Subject: [PATCH] some changes on product stat model & signals --- ...9_alter_deviceactivationcode_expires_at.py | 19 +++++++ .../0062_productstats_sale_unit_and_more.py | 28 ++++++++++ apps/product/models.py | 3 ++ apps/product/signals.py | 52 +++++++++++++++---- 4 files changed, 93 insertions(+), 9 deletions(-) create mode 100644 apps/pos_device/migrations/0019_alter_deviceactivationcode_expires_at.py create mode 100644 apps/product/migrations/0062_productstats_sale_unit_and_more.py diff --git a/apps/pos_device/migrations/0019_alter_deviceactivationcode_expires_at.py b/apps/pos_device/migrations/0019_alter_deviceactivationcode_expires_at.py new file mode 100644 index 0000000..53ca0da --- /dev/null +++ b/apps/pos_device/migrations/0019_alter_deviceactivationcode_expires_at.py @@ -0,0 +1,19 @@ +# Generated by Django 5.0 on 2025-08-02 11:03 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('pos_device', '0018_alter_deviceactivationcode_expires_at'), + ] + + operations = [ + migrations.AlterField( + model_name='deviceactivationcode', + name='expires_at', + field=models.DateTimeField(default=datetime.datetime(2025, 8, 2, 14, 33, 27, 93490)), + ), + ] diff --git a/apps/product/migrations/0062_productstats_sale_unit_and_more.py b/apps/product/migrations/0062_productstats_sale_unit_and_more.py new file mode 100644 index 0000000..e1c6e92 --- /dev/null +++ b/apps/product/migrations/0062_productstats_sale_unit_and_more.py @@ -0,0 +1,28 @@ +# Generated by Django 5.0 on 2025-08-02 11:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('product', '0061_historicalquotadistribution_parent_distribution_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='productstats', + name='sale_unit', + field=models.CharField(max_length=25, null=True), + ), + migrations.AddField( + model_name='productstats', + name='total_distribution_weight', + field=models.PositiveBigIntegerField(default=0), + ), + migrations.AddField( + model_name='productstats', + name='total_remaining_distribution_weight', + field=models.PositiveBigIntegerField(default=0), + ), + ] diff --git a/apps/product/models.py b/apps/product/models.py index e6aa7f0..3f9b620 100644 --- a/apps/product/models.py +++ b/apps/product/models.py @@ -149,11 +149,14 @@ class ProductStats(BaseModel): null=True ) quotas_number = models.PositiveBigIntegerField(default=0) + sale_unit = models.CharField(max_length=25, null=True) active_quotas_weight = models.PositiveBigIntegerField(default=0) closed_quotas_weight = models.PositiveBigIntegerField(default=0) total_quota_weight = models.PositiveBigIntegerField(default=0) total_remaining = models.PositiveBigIntegerField(default=0) + total_remaining_distribution_weight = models.PositiveBigIntegerField(default=0) total_distributed_weight = models.PositiveBigIntegerField(default=0) + total_distribution_weight = models.PositiveBigIntegerField(default=0) total_warehouse_entry = models.PositiveBigIntegerField(default=0) total_sold = models.PositiveBigIntegerField(default=0) total_transactions = models.PositiveBigIntegerField(default=0) diff --git a/apps/product/signals.py b/apps/product/signals.py index d29a138..3367a1d 100644 --- a/apps/product/signals.py +++ b/apps/product/signals.py @@ -60,15 +60,27 @@ def update_quota_remaining(sender, instance, **kwargs): remaining_distribution_weight(instance) -def update_product_stats(instance: Product): +def update_product_stats(instance: Product, distribution: QuotaDistribution = None): """ 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) + if ProductStats.objects.filter( + organization=organization, + product=instance, + sale_unit=distribution.quota.sale_unit.unit + ): + stat = instance.stats.get( + organization=organization, + product=instance, + sale_unit=distribution.quota.sale_unit.unit + ) else: - stat = ProductStats.objects.create(product=instance, organization=organization) + stat = ProductStats.objects.create( + product=instance, + organization=organization, + sale_unit=distribution.quota.sale_unit.unit + ) # number of quotas quotas_count = instance.quotas.filter(is_closed=False).count() # noqa @@ -91,22 +103,42 @@ def update_product_stats(instance: Product): total=models.Sum('remaining_weight') )['total'] or 0 + total_distribution_weight = QuotaDistribution.objects.filter( + quota__product_id=instance.id, + quota__is_closed=False, + quota__sale_unit=distribution.quota.sale_unit, + assigned_organization=distribution.assigned_organization + ).aggregate(total_weight=models.Sum('weight'))['total_weight'] or 0 + # product total distributed weight from quota total_distributed_weight = QuotaDistribution.objects.filter( quota__product_id=instance.id, - quota__is_closed=False + quota__is_closed=False, + quota__sale_unit=distribution.quota.sale_unit, + assigner_organization=distribution.assigner_organization ).aggregate(total_weight=models.Sum('weight'))['total_weight'] or 0 + total_remaining_distribution_weight = QuotaDistribution.objects.filter( + quota__product_id=instance.id, + quota__is_closed=False, + quota__sale_unit=distribution.quota.sale_unit, + assigner_organization=distribution.assigner_organization + ).aggregate(total_weight=models.Sum('remaining_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 + quota__is_closed=False, + quota__sale_unit=distribution.quota.sale_unit, + assigned_organization=distribution.assigned_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__is_closed=False, + quota__sale_unit=distribution.quota.sale_unit, + assigned_organization=distribution.assigned_organization ).aggregate(total_entry=models.Sum('warehouse_entry'))['total_entry'] or 0 stat.quotas_number = quotas_count @@ -114,7 +146,9 @@ def update_product_stats(instance: Product): stat.closed_quotas_weight = closed_quotas_weight stat.total_quota_weight = total_quotas_weight stat.total_remaining = total_remaining_quotas_weight + stat.total_remaining_distribution_weight = total_remaining_distribution_weight stat.total_distributed_weight = total_distributed_weight + stat.total_distribution_weight = total_distribution_weight stat.total_warehouse_entry = total_warehouse_entry stat.total_sold = total_sold stat.save(update_fields=[ @@ -168,8 +202,8 @@ def update_quota_stats(instance: Quota): @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_product_stats(instance.quota.product, instance) update_quota_stats(instance.quota) elif sender == InventoryQuotaSaleTransaction: - update_product_stats(instance.quota_distribution.quota.product) + update_product_stats(instance.quota_distribution.quota.product, instance.quota_distribution) update_quota_stats(instance.quota_distribution.quota)