Files
RasadDam_Backend/apps/herd/services/services.py

168 lines
6.3 KiB
Python

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
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
):
"""
:param rancher: Rancher instance
:param inventory_entry: InventoryEntry instance
:param distribution: QuotaDistribution 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 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)
return {
"total_weight": total_weight,
"remaining_weight": total_weight - rancher_remaining_usage,
"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()]
}