import json from apps.core.custom_middlewares.request_middleware import get_current_request_body from apps.product.models import QuotaDistribution, OrganizationQuotaStats, AttributeValue, Attribute, QuotaBrokerValue, \ Broker from apps.product.validators.quota_stats_validator import QuotaStatsValidator from apps.warehouse.models import InventoryEntry def import_price_features(data, assigned_stat, quota): """ create price attributes data & broker pricing value for every distribution """ assigned_stat.attribute_values.all().delete() assigned_stat.broker_values.all().delete() if 'price_attributes_data' and 'broker_data' in data.keys(): attr_price_values = [AttributeValue( attribute=Attribute.objects.get(id=attr['attribute']), value=attr['value'], quota=quota, org_quota_stat=assigned_stat ) for attr in data['price_attributes_data']] AttributeValue.objects.bulk_create(attr_price_values) # bulk create broker_price_values = [ QuotaBrokerValue( quota=quota, broker=Broker.objects.get(id=broker['broker']), value=broker['value'], org_quota_stat=assigned_stat ) for broker in data['broker_data'] ] QuotaBrokerValue.objects.bulk_create(broker_price_values) # bulk create quota.edited_pricing_features = True quota.save(update_fields=['edited_pricing_features']) class QuotaStatsService: @staticmethod def apply_distribution(distribution: QuotaDistribution): quota = distribution.quota # origin org assigner = distribution.assigner_organization if assigner.type.key == 'ADM': assigner = quota.registerer_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, 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() # create pricing attributes and broker pricing data data = json.loads(get_current_request_body().decode()) import_price_features(data, assigned_stat, quota) @staticmethod def update_distribution(distribution: QuotaDistribution, old_weight: int): diff = distribution.weight - old_weight 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 ) # create pricing attributes and broker pricing data data = json.loads(get_current_request_body().decode()) import_price_features(data, assigned_stat, quota) if diff == 0: return 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'])