from apps.product.models import QuotaDistribution, OrganizationQuotaStats from apps.product.validators.quota_stats_validator import QuotaStatsValidator from apps.warehouse.models import InventoryEntry 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, quota=quota, ) if created: assigner_stat.stat_type = 'distribution' assigner_stat.save() if assigner_stat.stat_type == 'distribution': assigner_stat.remaining_amount -= distribution.weight assigner_stat.total_distributed += distribution.weight assigner_stat.save() # ============== destination ================ assigned_stat, _ = OrganizationQuotaStats.objects.get_or_create( organization=assigned, quota=quota, stat_type='distribution' ) assigned_stat.total_amount += distribution.weight assigned_stat.remaining_amount += distribution.weight assigned_stat.distributions.add(distribution) assigned_stat.save() @staticmethod def update_distribution(distribution: QuotaDistribution, old_weight: int): diff = distribution.weight - old_weight if diff == 0: return quota = distribution.quota 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 ) assigned_stat = OrganizationQuotaStats.objects.get( organization=assigned, quota=quota ) if assigner_stat.stat_type == 'distribution': # if diff > 0 it is added to destination assigner_stat.remaining_amount -= diff assigner_stat.total_distributed += diff assigner_stat.save() assigned_stat.total_amount += diff assigned_stat.remaining_amount += diff assigned_stat.save() @staticmethod def delete_distribution(distribution: QuotaDistribution): quota = distribution.quota # origin assigner_stat = OrganizationQuotaStats.objects.get( organization=distribution.assigner_organization, quota=quota ) if assigner_stat.stat_type == 'distribution': assigner_stat.remaining_amount += distribution.weight assigner_stat.total_distributed -= distribution.weight assigner_stat.save() # destination assigned_stat = OrganizationQuotaStats.objects.get( organization=distribution.assigned_organization, quota=quota ) assigned_stat.total_amount -= distribution.weight assigned_stat.remaining_amount -= distribution.weight assigned_stat.distributions.remove(distribution) assigned_stat.save() @staticmethod def apply_inventory_entry(entry: InventoryEntry, created): quota = entry.quota weight = entry.weight if not created: old_weight = entry._old_weight # noqa diff = weight - old_weight else: diff = weight print("0000", diff) QuotaStatsService._propagate_inventory( organization=entry.organization, quota=quota, diff=diff ) @staticmethod def remove_inventory_entry(entry: InventoryEntry): quota = entry.quota weight = entry.weight QuotaStatsService._propagate_inventory( organization=entry.organization, quota=quota, diff=-weight ) @staticmethod def _propagate_inventory(organization, quota, diff): org = organization stat_queryset = OrganizationQuotaStats.objects.select_related('quota', 'organization') update_my_remaining_stat = True parent_orgs = [] while org: parent_orgs.append(org) org = org.parent_organization parent_orgs_ids = [org.id for org in parent_orgs] target_org_ids = set(parent_orgs_ids) if quota.registerer_organization.id not in target_org_ids: target_org_ids.add(quota.registerer_organization.id) stats = (stat_queryset.filter( quota=quota, organization__in=target_org_ids )) for stat in stats: stat.inventory_received = (stat.inventory_received or 0) + diff # just update my own stat remaining quota weight if update_my_remaining_stat: stat.remaining_amount -= diff update_my_remaining_stat = False if stat.inventory_received < 0: stat.inventory_received = 0 OrganizationQuotaStats.objects.bulk_update(stats, ['inventory_received', 'remaining_amount'])