import typing from django.db.models import Count, Q, Value from django.db.models import Sum from django.db.models.functions import Coalesce from apps.herd.models import Rancher from apps.herd.services.rancher_service import RancherService from apps.livestock.models import LiveStock, TemporaryLiveStock from apps.product.models import Quota, QuotaDistribution, OrganizationQuotaStats from apps.warehouse.models import ( InventoryEntry, InventoryQuotaSaleItem ) LIVESTOCK_GROPES = { 'industrial': 'I', # صنعتی 'rural': 'V', # روستایی 'nomadic': 'N' # عشایری } def get_rancher_statistics(rancher: Rancher = None) -> typing.Any: """ get statistics of a rancher """ # noqa # get rancher livestock livestocks = LiveStock.objects.filter(herd__rancher=rancher) # noqa # get rancher temporary livestock , rancher will have no herd temporary_livestock = TemporaryLiveStock.objects.filter(rancher=rancher) if livestocks.exists(): stats = livestocks.aggregate( herd_count=Count("herd", distinct=True), light_count=Count('id', filter=Q(weight_type='L')), heavy_count=Count('id', filter=Q(weight_type='H')), sheep=Count('id', filter=Q(type__name='گوسفند')), # noqa goat=Count('id', filter=Q(type__name='بز')), cow=Count('id', filter=Q(type__name='گاو')), camel=Count('id', filter=Q(type__name='شتر')), horse=Count('id', filter=Q(type__name='اسب')), ) else: stats = temporary_livestock.aggregate( light_count=Coalesce(Sum('count', filter=Q(livestock_type__weight_type='L')), Value(0)), heavy_count=Coalesce(Sum('count', filter=Q(livestock_type__weight_type='H')), Value(0)), sheep=Coalesce(Sum('count', filter=Q(livestock_type__name='گوسفند')), Value(0)), # noqa goat=Coalesce(Sum('count', filter=Q(livestock_type__name='بز')), Value(0)), cow=Coalesce(Sum('count', filter=Q(livestock_type__name='گاو')), Value(0)), camel=Coalesce(Sum('count', filter=Q(livestock_type__name='شتر')), Value(0)), horse=Coalesce(Sum('count', filter=Q(livestock_type__name='اسب')), Value(0)), ) return [{'name': key, 'value': value} for key, value in stats.items()], stats def get_rancher_statistic_by_herd(rancher: Rancher = None) -> typing.Any: """ get statistics of a rancher by his herds """ # noqa herds = rancher.herd.all() if herds.exists(): stats = herds.aggregate( herd_count=Count("id", distinct=True), light_count=Sum('light_livestock_number'), heavy_count=Sum('heavy_livestock_number'), sheep=Sum('light_livestock_number'), # noqa cow=Sum('heavy_livestock_number'), ) else: stats = { 'herd_count': 0, 'light_count': 0, 'heavy_count': 0, 'sheep': 0, 'cow': 0, } return [{'name': key, 'value': value} for key, value in stats.items()], stats def rancher_quota_weight( rancher: Rancher, inventory_entry: InventoryEntry = None, distribution: QuotaDistribution = None, quota: Quota = None, quota_stat: OrganizationQuotaStats = None ): """ :param rancher: Rancher instance :param inventory_entry: InventoryEntry instance :param distribution: QuotaDistribution instance :param quota: Quota instance :param quota_stat: OrganizationQuotaStat instance :return: dict {total, by_type} """ live_stock_meta = { "گوسفند": "sheep", # noqa "بز": "goat", "گاو": "cow", "شتر": "camel", "اسب": "horse" } if inventory_entry: quota: Quota = inventory_entry.distribution.quota elif distribution: quota: Quota = distribution.quota else: quota: Quota = quota # list of quota live stock allocations allocations = list(quota.livestock_allocations.all().select_related('livestock_type')) # list of quota incentive plans incentive_plans = list(quota.incentive_assignments.all().select_related('livestock_type')) # list of rancher herds herds = rancher.herd.all() herd_livestock_gropes = [herd.activity if herd.activity else 'V' for herd in herds] livestock_counts_list, livestock_counts_dict = get_rancher_statistic_by_herd(rancher) total_weight = 0 merged = {} # calculate quota base weight by livestock type & base total weight for item in allocations: # noqa if item.livestock_type: if LIVESTOCK_GROPES[item.livestock_group] in herd_livestock_gropes: animal_type_fa = item.livestock_type.name animal_type_en = item.livestock_type.en_name per_head = item.quantity_kg count = livestock_counts_dict.get(live_stock_meta.get(animal_type_fa), 0) weight = per_head * count total_weight += weight if animal_type_en not in merged: merged[animal_type_en] = { "name_fa": animal_type_fa, "weight": weight, "type": item.livestock_type.weight_type } else: merged[animal_type_en]['weight'] += weight # calculate rancher incentive plans weight by livestock type & add it to total_weight for item in incentive_plans: rancher_plans = item.incentive_plan.rancher_plans.select_related( 'rancher', 'livestock_type' ).filter(rancher=rancher, livestock_type=item.livestock_type) if rancher_plans.exists(): # multiple count of rancher livestock on incentive plan & # incentive plan quantity by this livestock type rancher_plan_weight = rancher_plans.first().allowed_quantity * item.quantity_kg total_weight += rancher_plan_weight # get rancher remaining usage of quota for purchase rancher_remaining_usage = RancherService.get_total_used_weight( rancher, InventoryQuotaSaleItem, quota_stat=quota_stat ) if total_weight - rancher_remaining_usage < 0: remaining_weight = 0 free_sale = rancher_remaining_usage - total_weight total_purchase = free_sale + total_weight else: remaining_weight = total_weight - rancher_remaining_usage free_sale = 0 total_purchase = total_weight - remaining_weight return { "total_weight": total_weight, "remaining_weight": remaining_weight, 'free_sale': free_sale, 'total_purchase': total_purchase, "rancher_temporary_livestock": rancher.without_herd, "by_type": [{ "name": key, "name_fa": value['name_fa'], "weight": value['weight'], "type": value['type'] } for key, value in merged.items()] }