add - import validator for organization quota stats

This commit is contained in:
2025-11-17 16:46:59 +03:30
parent 7ffbacc331
commit d8f6eaf243
5 changed files with 91 additions and 6 deletions

View File

@@ -1,15 +1,23 @@
from apps.product.models import QuotaDistribution, OrganizationQuotaStats
from apps.product.validators.quota_stats_validator import QuotaStatsValidator
class QuotaStatsService:
@staticmethod
def apply_distribution(distribution: QuotaDistribution):
quota = distribution.quota
print("ssss")
# origin org
assigner = distribution.assigner_organization
# destination org
assigned = distribution.assigned_organization
QuotaStatsValidator.validate_assigner_has_enough(
assigner_org=assigner,
quota=quota,
amount=distribution.weight
)
# ================ origin ================
assigner_stat, created = OrganizationQuotaStats.objects.get_or_create(
organization=assigner,
@@ -46,6 +54,14 @@ class QuotaStatsService:
assigner = distribution.assigner_organization
assigned = distribution.assigned_organization
QuotaStatsValidator.validate_distribution_update(
assigner_org=assigner,
assigned_org=assigned,
quota=quota,
old_amount=old_weight,
new_amount=distribution.weight
)
assigner_stat = OrganizationQuotaStats.objects.get(
organization=assigner,
quota=quota
@@ -57,13 +73,9 @@ class QuotaStatsService:
if assigner_stat.stat_type == 'distribution':
# if diff > 0 it is added to destination
assigner_stat.remaining_amount -= diff
print("distributed : ", assigner_stat.total_distributed)
assigner_stat.total_distributed += diff
print(assigner_stat.total_distributed, diff)
assigner_stat.save()
print(assigned_stat.total_amount)
assigned_stat.total_amount += diff
print(assigned_stat.total_amount)
assigned_stat.remaining_amount += diff
assigned_stat.save()

View File

@@ -5,6 +5,7 @@ from django.db.models import Sum, Q
from django.db.models.signals import post_save, post_delete, post_init
from django.dispatch import receiver
from apps.product.validators.quota_stats_validator import QuotaStatsValidator
from apps.warehouse.models import (
InventoryQuotaSaleTransaction,
InventoryEntry
@@ -80,7 +81,11 @@ def update_product_stats(instance: Product, distribution: QuotaDistribution = No
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
)
if ProductStats.objects.filter(
organization=organization,
product=instance,

View File

View File

@@ -0,0 +1,60 @@
from django.apps import apps
from django.core.exceptions import ValidationError
from rest_framework.exceptions import APIException
def get_model(app_label, model_name):
return apps.get_model(app_label, model_name)
class QuotaStatsValidator:
"""
Validator static methods for distribution/sale/quota edits.
"""
@staticmethod
def _get_stat(quota, organization):
organization_quota_stats = get_model("product", "OrganizationQuotaStats")
return organization_quota_stats.objects.filter(quota=quota, organization=organization).first()
@staticmethod
def validate_assigner_has_enough(assigner_org, quota, amount, allow_zero=False):
"""
if organization has enough remaining weight
"""
stat = QuotaStatsValidator._get_stat(quota, assigner_org)
if not stat:
raise APIException(f"Organization {assigner_org} has no quota record for quota {quota}.")
remaining = getattr(stat, "remaining_amount", None)
if remaining is None:
# fallback to quota.remaining_weight subtraction from totals
raise APIException("remaining_amount field missing in OrganizationQuotaStats.")
if amount < 0:
raise APIException("Amount must be non-negative.")
if remaining < amount and not allow_zero:
raise APIException(
f"Assigning {amount} exceeds remaining amount {remaining} for organization {assigner_org}."
)
@staticmethod
def validate_distribution_create(assigner_org, assigned_org, quota, amount, parent_distribution=None):
# rule: assigner must have enough remaining weight
QuotaStatsValidator.validate_assigner_has_enough(assigner_org, quota, amount)
@staticmethod
def validate_distribution_update(assigner_org, assigned_org, quota, old_amount, new_amount,
parent_distribution=None):
# if diff is positive we must check
diff = new_amount - (old_amount or 0)
if diff > 0:
QuotaStatsValidator.validate_assigner_has_enough(assigner_org, quota, diff)
@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.")

View File

@@ -1,4 +1,5 @@
from rest_framework import serializers
from rest_framework.exceptions import APIException
from apps.livestock.web.api.v1.serializers import LiveStockTypeSerializer
from apps.product import models as product_models
@@ -10,6 +11,13 @@ class QuotaSerializer(serializers.ModelSerializer):
model = product_models.Quota
fields = '__all__'
def validate(self, attrs):
weight = attrs['quota_weight']
if self.instance:
if self.instance.quota_distributed < weight:
raise APIException("Quota weight cannot be less than distributed weight.")
return attrs
def to_representation(self, instance: product_models.Quota):
representation = super().to_representation(instance)