Files
Rasadyar_RSI/app/views.py
2026-02-03 10:26:42 +03:30

6036 lines
267 KiB
Python
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import datetime
import json
import random
import string
from this import d
import uuid
from collections import defaultdict
from io import BytesIO
import boto3
import jdatetime
import openpyxl
import requests
from bs4 import BeautifulSoup
from django.db.models import Sum, Count, Avg, Q, Min, Max, Prefetch, F
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework import viewsets, status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework.views import APIView
from app.cityandprovince import iranprovince, irancity
from app.filtersets import PoultryFilterSet, PoultryHatchingFilterSet, TransportingChickenDetailFilterSet, \
PoultryInfoFilterSet, HatchingCalculationsFilterSet, HatchingsFilterSet, TransportingDetailFilterSet, \
KillHouseFilterSet, TransportingDetailCustomFilterSet, CustomHatchingsFilterSet, TransportCarcassDetailFilterSet, \
DriverFilterSet, GuildsFilterSet, AllProductsTransportFilterSet
from app.helper import SSLAdapter, get_hatching_permit_code, normalize_persian_arabic_text, apply_date_filter
from app.models import Poultry, PoultryHatching, TransportingChickenDetail, Hatching, TransportingDetail, KillHouse, \
ApkInfo, TransportCarcassDetail, Guilds, Driver, InquiryCredentials, AllProductsTransport, EvacuationDetail, \
RasadyarAppInfo
from app.serializers import PoultrySerializer, PoultryHatchingSerializer, TransportingChickenDetailSerializer, \
HatchingSerializer, HatchingCalculationSerializer, PoultryInfoSerializer, HatchingsSerializer, \
HatchingDetailSerializer, HatchingForUpdateSerializer, TransportingSerializer, TransportingDetailSerializer, \
KillHouseSerializer, HatchingAnalysisSerializer, HatchingAnalysisSerializerTwo, TransportingReportDashboard, \
TransportingForClearanceCodeSerializer, ApkInfoSerializer, TransportCarcassDetailSerializer, DriverSerializer, \
KillHouseForTransportCarcassSerializer, StewardForTransportCarcassSerializer, \
GuildsForTransportCarcassSerializer, KillHouseForTransportCarcassForRassadyaarSerializer, \
TransportingDetailForUpdateSerializer, InquiryCredentialsSerializer, AllProductsTransportSerializer, \
EvacuationDetailSerializer, RasadyarAppInfoSerializer, AllProductsTransportCustomSerializer
from authentication.models import Province
from helpers import CustomPagination, build_query, build_calculation, convert_to_miladi
class PoultryViewSet(viewsets.ModelViewSet):
queryset = Poultry.objects.all()
serializer_class = PoultrySerializer
permission_classes = [AllowAny]
pagination_class = CustomPagination
filterset_class = PoultryFilterSet
def create(self, request, *args, **kwargs):
data = request.data.get('Data', [])
for poultry in data:
registered_poultry = Poultry.objects.filter(UnitId=poultry['UnitId']).first()
if registered_poultry:
for key, value in poultry.items():
setattr(registered_poultry, key, value)
registered_poultry.save()
else:
Poultry.objects.create(**poultry)
return Response({"result": "با موفقیت ثبت شد"}, status=status.HTTP_201_CREATED)
def list(self, request, *args, **kwargs):
poultry = Poultry.objects.filter(trash=False)
value = request.GET.get('value')
if value:
poultry = poultry.filter(
build_query(self.filterset_class.Meta.fields, value)
)
page_size = request.query_params.get('page_size', None)
if page_size:
self.pagination_class.page_size = int(page_size)
page = self.paginate_queryset(poultry)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.serializer_class(poultry, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
# class PoultryDashboardViewSet(viewsets.ModelViewSet):
# queryset = Poultry.objects.filter(trash=False).only('id', 'Province', 'City').order_by('id')
# serializer_class = PoultrySerializer
# permission_classes = [AllowAny]
# filterset_class = PoultryInfoFilterSet
#
# def list(self, request, *args, **kwargs):
# poultries = self.queryset.filter(Province__isnull=False)
# hatchings = Hatching.objects.filter(trash=False).order_by('id')
# search = request.GET.get('search')
# province = request.GET.get('province')
# city = request.GET.get('city')
# if province:
# poultries = poultries.filter(Province__icontains=province)
# hatchings = Hatching.objects.filter(ProvinceName=province, trash=False).only('CityName',
# 'ProvinceName').order_by('id')
#
# if city:
# poultries = poultries.filter(City__icontains=city)
# hatchings = Hatching.objects.filter(CityName=city, trash=False).order_by('id')
#
# if search:
# if search != 'undefined' and search.strip():
# poultries = poultries.filter(
# build_query(self.filterset_class.Meta.fields, search)
# )
# province = len(set(poultries.values_list('LocationIdProvince', flat=True)))
# city = len(set(poultries.values_list('LocationIdCity', flat=True)))
# active_hatchings = hatchings.filter(Age__lte=70, trash=False).order_by('id')
# bars = TransportingDetail.objects.filter(hatching__in=hatchings, trash=False).order_by('id')
# active_hatchings_bars = bars.filter(hatching__in=active_hatchings, trash=False).order_by('id')
# total_active_hatching_quantity = active_hatchings.aggregate(total=Sum('ChickCountSum'))['total'] or 0
# total_active_hatching_evacuation = active_hatchings.aggregate(total=Sum('Evacuation'))['total'] or 0
# total_active_hatching_killing_quantity = active_hatchings_bars.aggregate(total=Sum('GoodAmount'))['total'] or 0
# total_active_hatching_left_over = active_hatchings.aggregate(total=Sum('LeftOver'))['total'] or 0
# total_hatching_quantity = hatchings.aggregate(total=Sum('ChickCountSum'))['total'] or 0
# total_hatching_evacuation = hatchings.aggregate(total=Sum('Evacuation'))['total'] or 0
# total_hatching_killing_quantity = bars.aggregate(total=Sum('GoodAmount'))['total'] or 0
# total_hatching_left_over = hatchings.aggregate(total=Sum('LeftOver'))['total'] or 0
#
# result = {
# "poultry_count": poultries.count(),
# "total_hatching_count": hatchings.count(),
# "total_hatching_quantity": total_hatching_quantity,
# "total_hatching_evacuation": total_hatching_evacuation,
# "total_hatching_evacuation_percent": round((total_hatching_evacuation / total_hatching_quantity) * 100, 2),
# "total_hatching_killing_quantity": total_hatching_killing_quantity,
# "total_hatching_killing_quantity_percent": round(
# (total_hatching_killing_quantity / total_hatching_quantity) * 100, 2),
# "total_hatching_left_over": total_hatching_left_over,
# "total_hatching_left_over_percent": round(
# (total_hatching_left_over / total_hatching_quantity) * 100, 2),
# "total_hatching_killing_age": bars.aggregate(avg_age=Avg('Age'))['avg_age'] or 0,
# "province_count": province,
# "city_count": city,
# "total_active_hatching_count": active_hatchings.count(),
# "total_active_hatching_quantity": total_active_hatching_quantity,
# "total_active_hatching_evacuation": total_active_hatching_evacuation,
# "total_active_hatching_evacuation_percent": round(
# (total_active_hatching_evacuation / total_active_hatching_quantity) * 100, 2),
# "total_active_hatching_bars": active_hatchings_bars.count(),
# "total_active_hatching_killing_quantity": total_active_hatching_killing_quantity,
# "total_active_hatching_killing_quantity_percent": round(
# (total_active_hatching_killing_quantity / total_active_hatching_quantity) * 100, 2),
# "total_active_hatching_killing_age": active_hatchings_bars.aggregate(avg_age=Avg('Age'))['avg_age'] or 0,
# "total_active_hatching_left_over": active_hatchings.aggregate(total=Sum('LeftOver'))['total'] or 0,
# "total_active_hatching_left_over_percent": round(
# (total_active_hatching_left_over / total_active_hatching_quantity) * 100, 2),
# # "hatching_killing_persent": active_hatchings.aggregate(total=Sum('LeftOver'))['total'] or 0,
#
# }
# return Response(result, status=status.HTTP_200_OK)
class PoultryDashboardViewSet(viewsets.ModelViewSet):
queryset = Poultry.objects.filter(trash=False).only(
'id', 'Province', 'City', 'LocationIdProvince', 'LocationIdCity'
).order_by('id')
serializer_class = PoultrySerializer
permission_classes = [AllowAny]
filterset_class = PoultryInfoFilterSet
def _optimized_db_hits(self, request):
province = request.GET.get('province')
city = request.GET.get('city')
search = request.GET.get('search')
base_poultries = self.queryset.filter(Province__isnull=False)
base_hatchings = Hatching.objects.filter(trash=False)
if province:
base_poultries = base_poultries.filter(Province__icontains=province)
base_hatchings = base_hatchings.filter(ProvinceName=province)
if city:
base_poultries = base_poultries.filter(City__icontains=city)
base_hatchings = base_hatchings.filter(CityName=city)
if search and search != 'undefined' and search.strip():
base_poultries = base_poultries.filter(
build_query(self.filterset_class.Meta.fields, search)
)
hatchings_data = base_hatchings.aggregate(
total_count=Count('id'),
total_quantity=Sum('ChickCountSum'),
total_evacuation=Sum('Evacuation'),
total_left_over=Sum('LeftOver'),
active_count=Count('id', filter=Q(Age__lte=70)),
active_quantity=Sum('ChickCountSum', filter=Q(Age__lte=70)),
active_evacuation=Sum('Evacuation', filter=Q(Age__lte=70)),
active_left_over=Sum('LeftOver', filter=Q(Age__lte=70)),
active_ready_left_over=Sum('LeftOver', filter=Q(Age__gte=40, Age__lte=70)),
)
transporting_data = TransportingDetail.objects.filter(
hatching__in=base_hatchings,
trash=False
).aggregate(
total_killing=Sum('GoodAmount'),
total_killing_age=Avg('Age'),
active_killing=Sum('GoodAmount', filter=Q(hatching__Age__lte=70)),
active_killing_age=Avg('Age', filter=Q(hatching__Age__lte=70)),
)
location_stats = base_poultries.aggregate(
province_count=Count('LocationIdProvince', distinct=True),
city_count=Count('LocationIdCity', distinct=True),
)
return {
'poultry_count': base_poultries.count(),
**hatchings_data,
**transporting_data,
**location_stats,
'active_bars_count': base_hatchings.filter(Age__lte=70).count(),
}
def list(self, request, *args, **kwargs):
try:
data = self._optimized_db_hits(request)
total_quantity = data.get('total_quantity', 0) or 1
active_quantity = data.get('active_quantity', 0) or 1
result = {
"poultry_count": data['poultry_count'],
"province_count": data['province_count'],
"city_count": data['city_count'],
"total_hatching_count": data['total_count'],
"total_hatching_quantity": data['total_quantity'],
"total_hatching_evacuation": data['total_evacuation'],
"total_hatching_evacuation_percent": round((data['total_evacuation'] / total_quantity) * 100, 2),
"total_hatching_killing_quantity": data['total_killing'],
"total_hatching_killing_quantity_percent": round((data['total_killing'] / total_quantity) * 100, 2),
"total_hatching_left_over": data['total_left_over'],
"total_hatching_left_over_percent": round((data['total_left_over'] / total_quantity) * 100, 2),
"total_hatching_killing_age": data['total_killing_age'],
"total_active_hatching_count": data['active_count'],
"total_active_hatching_quantity": data['active_quantity'],
"total_active_hatching_evacuation": data['active_evacuation'],
"total_active_hatching_evacuation_percent": round((data['active_evacuation'] / active_quantity) * 100,
2),
"total_active_hatching_bars": data['active_bars_count'],
"total_active_hatching_killing_quantity": data['active_killing'],
"total_active_hatching_killing_quantity_percent": round(
(data['active_killing'] / active_quantity) * 100, 2),
"total_active_hatching_killing_age": data['active_killing_age'],
"total_active_hatching_left_over": data['active_left_over'],
"total_active_hatching_left_over_percent": round((data['active_left_over'] / active_quantity) * 100, 2),
"total_ready_active_hatching_left_over": data['active_ready_left_over'],
"total_ready_hatching_left_over_percent": round(
(data['active_ready_left_over'] / data['active_left_over']) * 100, 2),
}
return Response(result, status=status.HTTP_200_OK)
except Exception as e:
return Response(
{"error": "خطا در پردازش داده‌ها", "details": str(e)},
status=status.HTTP_500_INTERNAL_SERVER_ERROR
)
@api_view(['GET'])
@permission_classes([AllowAny])
@csrf_exempt
def all_province_detail_for_map(request):
provinces = list(Province.objects.values_list('name', flat=True))
hatchings = Hatching.objects.filter(
Age__gte=1,
Age__lte=65,
trash=False,
ProvinceName__in=provinces
).values('ProvinceName').annotate(
total_quantity=Sum('ChickCountSum'),
total_left_over=Sum('LeftOver')
)
active_hatchings = hatchings.filter(
Age__gte=30,
Age__lte=65
).values('ProvinceName').annotate(
total_left_over=Sum('LeftOver')
)
transportings = TransportingDetail.objects.filter(
hatching__in=Hatching.objects.filter(
Age__gte=1,
Age__lte=65,
trash=False,
ProvinceName__in=provinces
),
trash=False
).values('hatching__ProvinceName').annotate(
total_killing=Sum('GoodAmount')
)
hatching_dict = {h['ProvinceName']: h for h in hatchings}
active_hatching_dict = {h['ProvinceName']: h for h in active_hatchings}
transporting_dict = {t['hatching__ProvinceName']: t for t in transportings}
results = []
for province in provinces:
h_data = hatching_dict.get(province, {'total_quantity': 0, 'total_left_over': 0})
a_h_data = active_hatching_dict.get(province, {'total_left_over': 0})
t_data = transporting_dict.get(province, {'total_killing': 0})
total_quantity = h_data['total_quantity'] or 0
total_left = h_data['total_left_over'] or 0
total_active_left = a_h_data['total_left_over'] or 0
results.append({
"total_quantity": total_quantity,
"total_left_over": total_left,
"total_killed_quantity": t_data['total_killing'] or 0,
"total_hatching_left_over_percent": round(
(total_left / total_quantity * 100),
) if total_quantity > 0 else 0,
"province_name": province,
"total_active_left": total_active_left,
"total_active_left_percent": round(
(total_active_left / total_quantity * 100),
) if total_quantity > 0 else 0,
})
sorted_results = sorted(
results,
key=lambda x: x['total_quantity'],
reverse=True
)
return Response(sorted_results)
@api_view(['GET'])
@permission_classes([AllowAny])
@csrf_exempt
def dashboard_province_detail_for_map(request):
total_hatching = Hatching.objects.filter(
Age__gte=1,
Age__lte=65,
trash=False
).aggregate(
total_quantity=Sum('ChickCountSum'),
total_left_over=Sum('LeftOver')
)
total_active = Hatching.objects.filter(
Age__gte=30,
Age__lte=65,
trash=False
).aggregate(
total_active_left=Sum('LeftOver')
)
total_transporting = TransportingDetail.objects.filter(
hatching__in=Hatching.objects.filter(
Age__gte=1,
Age__lte=65,
trash=False
),
trash=False
).aggregate(
total_killing=Sum('GoodAmount')
)
total_quantity = total_hatching['total_quantity'] or 0
total_left = total_hatching['total_left_over'] or 0
total_active_left = total_active['total_active_left'] or 0
left_over_percent = round((total_left / total_quantity * 100)) if total_quantity > 0 else 0
total_active_left_percent = round((total_active_left / total_quantity * 100)) if total_quantity > 0 else 0
result = {
"total_quantity": total_quantity,
"total_left_over": total_left,
"total_killed_quantity": total_transporting['total_killing'] or 0,
"total_hatching_left_over_percent": left_over_percent,
"total_active_left": total_active_left,
"total_active_left_percent": total_active_left_percent,
}
return Response(result)
# class HatchingDashboardViewSet(viewsets.ModelViewSet):
# queryset = Hatching.objects.filter(trash=False).only('KillingAve', 'LeftOver', 'ProvinceName', 'CityName',
# 'SystemCode').order_by(
# 'id')
# serializer_class = HatchingSerializer
# permission_classes = [AllowAny]
# filterset_class = HatchingsFilterSet
#
# def list(self, request, *args, **kwargs):
# system_code = request.GET.get('system_code')
# search = request.GET.get('search')
# leftover = request.GET.get('leftover')
# province = request.GET.get('province')
# city = request.GET.get('city')
# killing_age = request.GET.get('killing_age')
#
# hatchings = self.queryset
# date1 = self.request.GET.get('date1')
# date2 = self.request.GET.get('date2')
# if date1 and date2:
# date1 = datetime.datetime.strptime(str(self.request.GET['date1']), '%Y-%m-%d').date()
#
# date2 = datetime.datetime.strptime(str(self.request.GET['date2']), '%Y-%m-%d').date()
#
# hatchings = hatchings.filter(Date__date__gte=date1, Date__date__lte=date2, trash=False)
#
# if killing_age:
# hatchings = hatchings.filter(KillingAve=int(killing_age), trash=False)
# if leftover:
# hatchings = hatchings.filter(LeftOver__gt=0, trash=False)
#
# if province:
# hatchings = hatchings.filter(ProvinceName=province)
#
# if system_code:
# hatchings = hatchings.filter(SystemCode=system_code)
#
# if city:
# hatchings = hatchings.filter(CityName=city)
#
#
#
# if search:
# if search != 'undefined' and search.strip():
# hatchings = hatchings.filter(
# build_query(self.filterset_class.Meta.fields, search)
# )
# active_hatchings = hatchings.filter(Age__lte=70, trash=False).order_by('id')
# bars = TransportingDetail.objects.filter(hatching__in=hatchings, trash=False).order_by('id')
# active_hatchings_bars = bars.filter(hatching__in=active_hatchings, trash=False).order_by('id')
# total_hatching_quantity = hatchings.aggregate(total=Sum('ChickCountSum'))['total'] or 0
# total_hatching_evacuation = hatchings.aggregate(total=Sum('Evacuation'))['total'] or 0
# total_hatching_killing_quantity = bars.aggregate(total=Sum('GoodAmount'))['total'] or 0
# total_hatching_left_over = hatchings.aggregate(total=Sum('LeftOver'))['total'] or 0
# total_active_hatching_quantity = active_hatchings.aggregate(total=Sum('ChickCountSum'))['total'] or 0
# total_active_hatching_evacuation = active_hatchings.aggregate(total=Sum('Evacuation'))['total'] or 0
# total_active_hatching_killing_quantity = active_hatchings_bars.aggregate(total=Sum('GoodAmount'))[
# 'total'] or 0
# total_active_hatching_left_over = active_hatchings.aggregate(total=Sum('LeftOver'))['total'] or 0
#
# result = {
# "total_hatching_count": hatchings.count(),
# "total_hatching_quantity": total_hatching_quantity,
# "total_hatching_evacuation": total_hatching_evacuation,
# "total_hatching_evacuation_percent": round((total_hatching_evacuation / total_hatching_quantity) * 100, 2) if total_hatching_quantity > 0 else 0,
# "total_hatching_killing_quantity": total_hatching_killing_quantity,
# "total_hatching_killing_quantity_percent": round(
# (total_hatching_killing_quantity / total_hatching_quantity) * 100, 2) if total_hatching_quantity > 0 else 0,
# "total_hatching_left_over": total_hatching_left_over,
# "total_hatching_left_over_percent": round((total_hatching_left_over / total_hatching_quantity) * 100, 2) if total_hatching_quantity > 0 else 0,
# "total_hatching_killing_age": bars.aggregate(avg_age=Avg('Age'))['avg_age'] or 0,
# "total_hatching_bars": active_hatchings_bars.count(),
# "total_active_hatching_count": active_hatchings.count(),
# "total_active_hatching_quantity": total_active_hatching_quantity,
# "total_active_hatching_evacuation": total_active_hatching_evacuation,
# "total_active_hatching_evacuation_percent": round(
# (total_active_hatching_evacuation / total_active_hatching_quantity) * 100, 2) if total_active_hatching_quantity > 0 else 0,
# "total_active_hatching_bars": active_hatchings_bars.count(),
# "total_active_hatching_killing_quantity": total_active_hatching_killing_quantity,
# "total_active_hatching_killing_quantity_percent": round(
# (total_active_hatching_killing_quantity / total_active_hatching_quantity) * 100, 2) if total_active_hatching_quantity > 0 else 0,
# "total_active_hatching_left_over": total_active_hatching_left_over,
# "total_active_hatching_left_over_percent": round(
# (total_active_hatching_left_over / total_active_hatching_quantity) * 100, 2) if total_active_hatching_quantity > 0 else 0,
# "total_active_hatching_killing_age": active_hatchings_bars.aggregate(avg_age=Avg('Age'))['avg_age'] or 0,
# "least_age": active_hatchings.order_by('Age').first().Age if active_hatchings else 0,
# "most_age": active_hatchings.order_by('Age').last().Age if active_hatchings else 0,
#
# }
# return Response(result, status=status.HTTP_200_OK)
class HatchingDashboardViewSet(viewsets.ModelViewSet):
queryset = Hatching.objects.filter(trash=False).only(
'id', 'KillingAve', 'LeftOver', 'ProvinceName', 'CityName',
'SystemCode', 'Date', 'Age', 'ChickCountSum', 'Evacuation'
).order_by('id')
serializer_class = HatchingSerializer
permission_classes = [AllowAny]
filterset_class = HatchingsFilterSet
def _apply_filters(self, queryset, request):
system_code = request.GET.get('system_code')
search = request.GET.get('search')
leftover = request.GET.get('leftover')
province = request.GET.get('province')
city = request.GET.get('city')
killing_age = request.GET.get('killing_age')
name = request.GET.get('name')
date1 = request.GET.get('date1')
date2 = request.GET.get('date2')
if date1 and date2:
try:
date1 = datetime.datetime.strptime(date1, '%Y-%m-%d').date()
date2 = datetime.datetime.strptime(date2, '%Y-%m-%d').date()
queryset = queryset.filter(Date__date__range=[date1, date2])
except ValueError:
pass
if killing_age:
queryset = queryset.filter(KillingAve=int(killing_age))
if leftover:
queryset = queryset.filter(LeftOver__gt=0)
if province:
queryset = queryset.filter(ProvinceName=province)
if system_code:
queryset = queryset.filter(SystemCode=system_code)
if city:
queryset = queryset.filter(CityName=city)
if name:
poultry = Poultry.objects.filter(
Q(UserName__contains=name) | Q(FirstName__contains=name) | Q(LastName__contains=name) | Q(
Mobile__contains=name) | Q(UnitName__contains=name)
, trash=False).first()
queryset = queryset.filter(poultry=poultry)
if search and search != 'undefined' and search.strip():
queryset = queryset.filter(
build_query(self.filterset_class.Meta.fields, search)
)
return queryset
def _calculate_metrics(self, hatchings):
hatchings = hatchings.prefetch_related(
Prefetch('transportingdetail_set',
queryset=TransportingDetail.objects.filter(trash=False))
)
active_hatchings = hatchings.filter(Age__lte=70)
main_stats = hatchings.aggregate(
total_count=Count('id'),
total_quantity=Sum('ChickCountSum'),
total_evacuation=Sum('Evacuation'),
total_left_over=Sum('LeftOver'),
active_count=Count('id', filter=Q(Age__lte=70)),
active_quantity=Sum('ChickCountSum', filter=Q(Age__lte=70)),
active_evacuation=Sum('Evacuation', filter=Q(Age__lte=70)),
active_left_over=Sum('LeftOver', filter=Q(Age__lte=70)),
active_ready_left_over=Sum('LeftOver', filter=Q(Age__gte=40, Age__lte=70)),
)
bars_stats = TransportingDetail.objects.filter(
hatching__in=hatchings,
trash=False
).aggregate(
total_killing=Sum('GoodAmount'),
avg_killing_age=Avg('Age'),
active_killing=Sum('GoodAmount', filter=Q(hatching__Age__lte=70)),
active_avg_age=Avg('Age', filter=Q(hatching__Age__lte=70)),
active_bars_count=Count('id'),
min_age=Min('Age'),
max_age=Max('Age')
)
return {**main_stats, **bars_stats}
def list(self, request, *args, **kwargs):
# try:
filtered_hatchings = self._apply_filters(self.queryset, request)
metrics = self._calculate_metrics(filtered_hatchings)
total_quantity = metrics.get('total_quantity', 0) or 1
active_quantity = metrics.get('active_quantity', 0) or 1
if filtered_hatchings and filtered_hatchings.first().poultry:
poultry_name = filtered_hatchings.first().poultry.UnitName
poultry_mobile = filtered_hatchings.first().poultry.Mobile
poultry_firstName = filtered_hatchings.first().poultry.FirstName
poultry_lastName = filtered_hatchings.first().poultry.LastName
poultry_userName = filtered_hatchings.first().poultry.UserName
else:
poultry_name = ''
poultry_mobile = ''
poultry_firstName = ''
poultry_lastName = ''
poultry_userName = ''
result = {
"poultry_name": poultry_name,
"poultry_mobile": poultry_mobile,
"poultry_firstName": poultry_firstName,
"poultry_lastName": poultry_lastName,
"poultry_userName": poultry_userName,
"total_hatching_count": metrics['total_count'] if metrics['total_count'] else 0,
"total_hatching_quantity": metrics['total_quantity'] if metrics['total_quantity'] else 0,
"total_hatching_evacuation": metrics['total_evacuation'] if metrics['total_evacuation'] else 0,
"total_hatching_evacuation_percent": round((metrics['total_evacuation'] / total_quantity) * 100, 2) if
metrics['total_evacuation'] else 0,
"total_hatching_killing_quantity": metrics['total_killing'] if metrics['total_killing'] else 0,
"total_hatching_killing_quantity_percent": round((metrics['total_killing'] / total_quantity) * 100, 2) if
metrics['total_killing'] else 0,
"total_hatching_left_over": metrics['total_left_over'] if metrics['total_killing'] else 0,
"total_hatching_left_over_percent": round((metrics['total_left_over'] / total_quantity) * 100, 2) if
metrics['total_left_over'] else 0,
"total_hatching_killing_age": metrics['avg_killing_age'] if metrics['avg_killing_age'] else 0,
"total_hatching_bars": metrics.get('active_bars_count', 0),
"total_active_hatching_count": metrics['active_count'] if metrics['active_count'] else 0,
"total_active_hatching_quantity": metrics['active_quantity'] if metrics['active_quantity'] else 0,
"total_active_hatching_evacuation": metrics['active_evacuation'] if metrics['active_evacuation'] else 0,
"total_active_hatching_evacuation_percent": round(
(metrics['active_evacuation'] / active_quantity) * 100, 2) if metrics['active_evacuation'] else 0,
"total_active_hatching_bars": metrics.get('active_bars_count', 0),
"total_active_hatching_killing_quantity": metrics['active_killing'] if metrics['active_killing'] else 0,
"total_active_hatching_killing_quantity_percent": round(
(metrics['active_killing'] / active_quantity) * 100, 2) if metrics['active_killing'] else 0,
"total_active_hatching_left_over": metrics['active_left_over'] if metrics['active_left_over'] else 0,
"total_active_hatching_left_over_percent": round((metrics['active_left_over'] / active_quantity) * 100,
2) if metrics['active_left_over'] else 0,
"total_ready_active_hatching_left_over": metrics['active_ready_left_over'] if metrics[
'active_ready_left_over'] else 0,
"total_ready_hatching_left_over_percent": round(
(metrics['active_ready_left_over'] / metrics['active_left_over']) * 100,
2) if metrics['active_ready_left_over'] else 0,
"total_active_hatching_killing_age": metrics['active_avg_age'] or 0,
"least_age": metrics.get('min_age', 0),
"most_age": metrics.get('max_age', 0),
}
return Response(result, status=status.HTTP_200_OK)
# except Exception as e:
# return Response(
# {"error": str(e)},
# status=status.HTTP_500_INTERNAL_SERVER_ERROR
# )
class PoultryHatchingDashboardViewSet(viewsets.ModelViewSet):
queryset = PoultryHatching.objects.all()
serializer_class = PoultryHatchingSerializer
permission_classes = [AllowAny]
filterset_class = PoultryHatchingFilterSet
def list(self, request, *args, **kwargs):
hatchings = PoultryHatching.objects.filter(trash=False).order_by('Date')
date1 = request.GET.get('date1')
date2 = request.GET.get('date2')
if date1 and date2:
date1 = datetime.datetime.strptime(str(request.GET['date1']), '%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(request.GET['date2']), '%Y-%m-%d').date()
hatchings = hatchings.filter(Date__date__gte=date1, Date__date__lte=date2)
search = request.GET.get('search')
if search:
if search != 'undefined' and search.strip():
hatchings = hatchings.filter(
build_query(self.filterset_class.Meta.fields, search)
)
poultry = Poultry.objects.filter(pk__in=hatchings.values_list('poultry', flat=True), trash=False)
transports = TransportingChickenDetail.objects.filter(hatching__isnull=False, trash=False)
hatching_quantity = hatchings.aggregate(total=Sum('HatchingCount'))['total'] or 0
evacuation_count = hatchings.aggregate(total=Sum('EvacuationCount'))['total'] or 0
bars_quantity = transports.aggregate(total=Sum('GoodAmount'))['total'] or 0
result = {
"poultry": len(poultry),
"hatchings": len(hatchings),
"hatching_quantity": hatching_quantity,
"evacuation_count": evacuation_count,
"hatching_remain_quantity": hatching_quantity - evacuation_count,
"bars": len(transports),
"bars_quantity": bars_quantity,
}
return Response(result, status=status.HTTP_200_OK)
class PoultryHatchingViewSet(viewsets.ModelViewSet):
queryset = PoultryHatching.objects.all()
serializer_class = PoultryHatchingSerializer
permission_classes = [AllowAny]
pagination_class = CustomPagination
filterset_class = PoultryHatchingFilterSet
def create(self, request, *args, **kwargs):
data = request.data['Data']
request.data.pop('Data')
for hatching_data in data:
registered_hatching = PoultryHatching.objects.filter(DesCertId=hatching_data['DesCertId']).first()
if registered_hatching:
for key, value in hatching_data.items():
setattr(registered_hatching, key, value)
registered_hatching.save()
else:
hatching = PoultryHatching.objects.create(**hatching_data)
poultry = Poultry.objects.filter(UnitId=hatching_data['UnitId']).first()
if poultry:
hatching.poultry = poultry
hatching.save()
return Response({"result": "با موفقیت ثبت شد"}, status=status.HTTP_201_CREATED)
def list(self, request, *args, **kwargs):
hatchings = PoultryHatching.objects.filter(trash=False).order_by('Date')
# hatchings = PoultryHatching.objects.filter(
# pk__in=TransportingChickenDetail.objects.filter(trash=False).values_list('hatching', flat=True),
# trash=False).order_by('Date')
date1 = request.GET.get('date1')
date2 = request.GET.get('date2')
if date1 and date2:
date1 = datetime.datetime.strptime(str(request.GET['date1']), '%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(request.GET['date2']), '%Y-%m-%d').date()
hatchings = hatchings.filter(Date__date__gte=date1, Date__date__lte=date2)
search = request.GET.get('search')
if search:
if search != 'undefined' and search.strip():
hatchings = hatchings.filter(
build_query(self.filterset_class.Meta.fields, search)
)
page_size = request.query_params.get('page_size', None)
if page_size:
self.pagination_class.page_size = int(page_size)
page = self.paginate_queryset(hatchings)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.serializer_class(hatchings, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
class HatchingsViewSet(viewsets.ModelViewSet):
queryset = Hatching.objects.filter(trash=False)
serializer_class = HatchingsSerializer
permission_classes = [AllowAny]
pagination_class = CustomPagination
filterset_class = HatchingsFilterSet
def set_filters(self):
filters = {}
system_code = self.request.GET.get('system_code')
city = self.request.GET.get('city')
province = self.request.GET.get('province')
age = self.request.GET.get('age')
killing_age = self.request.GET.get('killing_age')
date1 = self.request.GET.get('date1')
date2 = self.request.GET.get('date2')
if date1 and date2:
date1 = datetime.datetime.strptime(str(self.request.GET['date1']), '%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(self.request.GET['date2']), '%Y-%m-%d').date()
filters['Date__date__gte'] = date1
filters['Date__date__lte'] = date2
if killing_age:
filters['KillingAve'] = int(killing_age)
if system_code:
filters['SystemCode'] = system_code
if age:
filters['Age__exact'] = age
if city:
filters['CityName__icontains'] = city
if province:
filters['ProvinceName__icontains'] = province
return filters
def create(self, request, *args, **kwargs):
BREED_STANDARDIZATION = {
'آربراکرز (آ<><D8A2>لاس)': 'آربراکرز (آپلاس)',
'آربراک<EFBFBD><EFBFBD>ز (آپلاس)': 'آربراکرز (آپلاس)',
'آربر<EFBFBD><EFBFBD>کرز (آپلاس)': 'آربراکرز (آپلاس)',
'را<EFBFBD><EFBFBD>': 'راس',
'ر<EFBFBD><EFBFBD>س': 'راس',
'<EFBFBD><EFBFBD>اس': 'راس',
'آ<EFBFBD><EFBFBD>ین': 'آرین',
'آر<EFBFBD><EFBFBD>ن': 'آرین',
'ایندین ریو<DB8C><D988>': 'ایندین ریور',
'ایند<EFBFBD><EFBFBD>ن ریور': 'ایندین ریور',
'ک<EFBFBD><EFBFBD>ب': 'کاب'
}
if int(request.data['GoodSum']) > 0:
poultry_data = {}
same_keys = [
'UnitName', 'SystemCode', 'EpidemiologicCode', 'LocationNameProvince',
'LocationNameCity', 'RegDate', 'RegDateShamsi', 'RegDateShamsiWithTime',
'RegDateShamsiOnlyTime', 'StringId', 'ModalCss', 'GridContainerParametersModel',
'MenuUserAccess', 'LogTableName', 'LogTableAlias', 'PageTitle',
'PartIdCode', 'UnitTypeName'
]
for key in same_keys:
if key in request.data and request.data[key] is not None:
poultry_data[key] = request.data[key]
bool_keys = ['IsPersisted', 'AllowInsert', 'AllowUpdate', 'UnitIsActive']
for key in bool_keys:
if key in request.data:
poultry_data[key] = bool(request.data[key])
if 'MenuUserAccessId' in request.data:
try:
poultry_data['MenuUserAccessId'] = int(request.data['MenuUserAccessId'])
except (ValueError, TypeError):
poultry_data['MenuUserAccessId'] = -1
if 'UnitPostalCode' in request.data:
poultry_data['PostalCode'] = request.data['UnitPostalCode']
if 'ProvinceName' in request.data:
poultry_data['Province'] = request.data['ProvinceName']
if 'CityName' in request.data:
poultry_data['City'] = request.data['CityName']
if 'PersonFullName' in request.data and 'UserName' not in poultry_data:
poultry_data['UserName'] = request.data['PersonFullName']
system_code = request.data.get('SystemCode')
if system_code:
poultry = Poultry.objects.filter(SystemCode=system_code).first()
if not poultry:
try:
poultry = Poultry.objects.create(**poultry_data)
poultry.save()
except Exception as e:
print(f"Error creating poultry: {e}")
else:
update_fields = []
for key, value in poultry_data.items():
if hasattr(poultry, key):
current_value = getattr(poultry, key)
if current_value != value:
setattr(poultry, key, value)
update_fields.append(key)
if update_fields:
try:
poultry.save(update_fields=update_fields)
except :
pass
poultry = Poultry.objects.filter(SystemCode=system_code).first()
bars = request.data.get('Transports', [])
if 'Transports' in request.data:
request.data.pop('Transports')
evacuation_details = request.data.get('EvacuationDetail', [])
if 'EvacuationDetail' in request.data:
request.data.pop('EvacuationDetail')
hatching = Hatching.objects.filter(RequestCode=request.data['RequestCode']).first()
print({'1': request.data['ProvinceName']})
if hatching:
for key, value in request.data.items():
setattr(hatching, key, value)
if hatching.poultry is None:
hatching.poultry=poultry
hatching.save()
else:
hatchings = Hatching.objects.filter(poultry=poultry).order_by('id').last()
period = hatchings.Period + 1 if hatchings else 1
request.data['Period'] = period
hatching = Hatching.objects.create(**request.data)
hatching.ArchiveDate = hatching.Date + datetime.timedelta(days=76)
if poultry:
hatching.poultry = poultry
hatching.save()
allowed_evacuation_fields = {
'PartIdCode', 'RequestId', 'MoReportId', 'ReportType', 'ReportTypeString',
'ReportDate', 'ReportDateShamsi', 'MoReason', 'MoDate', 'MoDateShamsi',
'MoStartDay', 'MoEndDay', 'MoReportSubId', 'ReportStatus', 'GoodCount',
'Message', 'ErrorCode', 'IsDeleted', 'RegDate', 'RegDateShamsi',
'RegDateShamsiWithTime', 'RegDateShamsiOnlyTime', 'ExternalId', 'StringId',
'IsPersisted', 'AllowInsert', 'AllowUpdate', 'ModalCss',
'GridContainerParametersModel', 'MenuUserAccess', 'MenuUserAccessId',
'LogTableName', 'LogTableAlias', 'PageTitle'
}
if evacuation_details:
cleaned_payload = []
external_ids = []
for evacuation_data in evacuation_details:
clean_data = {
k: v for k, v in evacuation_data.items()
if k in allowed_evacuation_fields or k == 'Id'
}
external_id = clean_data.pop('Id', None)
if external_id is not None:
clean_data['ExternalId'] = external_id
external_ids.append(external_id)
cleaned_payload.append((external_id, clean_data))
existing_map = {}
if external_ids:
existing_qs = EvacuationDetail.objects.filter(
ExternalId__in=external_ids,
trash=False
)
existing_map = {ev.ExternalId: ev for ev in existing_qs}
bulk_create = []
for external_id, clean_data in cleaned_payload:
if external_id:
evacuation = existing_map.get(external_id)
if evacuation and 'GoodCount' in clean_data:
evacuation.GoodCount = clean_data['GoodCount']
evacuation.hatching = hatching
evacuation.save(update_fields=['GoodCount', 'hatching'])
continue
clean_data['hatching'] = hatching
bulk_create.append(EvacuationDetail(**clean_data))
if bulk_create:
EvacuationDetail.objects.bulk_create(bulk_create)
if bars:
for transport_data in bars:
transport = TransportingDetail.objects.filter(
TrackingCode=transport_data['TrackingCode']).first()
if transport:
for key, value in transport_data.items():
setattr(transport, key, value)
transport.save()
else:
transport = TransportingDetail.objects.create(**transport_data)
kill_house = KillHouse.objects.filter(PartIdCode=transport.DesPartIdCode, trash=False).first()
transport.hatching = hatching
if kill_house:
transport.Province = kill_house.Province
transport.City = kill_house.City
if hatching.poultry.LocationIdProvince != kill_house.ProvinceId:
transport.Out = True
transport.save()
transport.Age = (transport.Date.date() - transport.hatching.Date.date()).days + 1
transport.save()
bars = TransportingDetail.objects.filter(trash=False, hatching=hatching)
bars_quantity = bars.filter(TrackingStatusDescription='تایید تخلیه').aggregate(total=Sum('GoodAmount'))[
'total'] or 0
ave_age = int(bars.aggregate(avg_age=Avg('Age'))[
'avg_age'] or 0)
hatching.LeftOver = hatching.ChickCountSum - (hatching.Evacuation + bars_quantity) if (
hatching.ChickCountSum - (
hatching.Evacuation + bars_quantity)) > 0 else 0
print({'2': hatching.ProvinceName})
if hatching.PedigreeName in BREED_STANDARDIZATION:
hatching.PedigreeName = BREED_STANDARDIZATION[hatching.PedigreeName]
hatching.KillingAve = ave_age
hatching.samasat_discharge_percentage = int(
((hatching.Evacuation + bars_quantity) / hatching.ChickCountSum) * 100)
hatching.save()
else:
print('تعداد حمل صفر است')
return Response({"result": "با موفقیت ثبت شد"}, status=status.HTTP_201_CREATED)
def list(self, request, *args, **kwargs):
state = self.request.GET.get('state')
hatchings = Hatching.objects.filter(**self.set_filters())
if state:
if state == 'pending':
hatchings = hatchings.filter(Age__lte=70)
else:
hatchings = hatchings.filter(Age__gt=70)
search = request.GET.get('search')
if search:
if search != 'undefined' and search.strip():
hatchings = hatchings.filter(
build_query(self.filterset_class.Meta.fields, search)
)
page_size = request.query_params.get('page_size', None)
if page_size:
self.pagination_class.page_size = int(page_size)
page = self.paginate_queryset(hatchings)
if page is not None:
serializer = HatchingDetailSerializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = HatchingDetailSerializer(hatchings, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
class HatchingsCustomViewSet(viewsets.ModelViewSet):
queryset = Hatching.objects.filter(trash=False)
serializer_class = HatchingsSerializer
permission_classes = [AllowAny]
pagination_class = CustomPagination
filterset_class = CustomHatchingsFilterSet
def create(self, request, *args, **kwargs):
BREED_STANDARDIZATION = {
'آربراکرز (آ<><D8A2>لاس)': 'آربراکرز (آپلاس)',
'آربراک<EFBFBD><EFBFBD>ز (آپلاس)': 'آربراکرز (آپلاس)',
'آربر<EFBFBD><EFBFBD>کرز (آپلاس)': 'آربراکرز (آپلاس)',
'را<EFBFBD><EFBFBD>': 'راس',
'ر<EFBFBD><EFBFBD>س': 'راس',
'<EFBFBD><EFBFBD>اس': 'راس',
'آ<EFBFBD><EFBFBD>ین': 'آرین',
'آر<EFBFBD><EFBFBD>ن': 'آرین',
'ایندین ریو<DB8C><D988>': 'ایندین ریور',
'ایند<EFBFBD><EFBFBD>ن ریور': 'ایندین ریور',
'ک<EFBFBD><EFBFBD>ب': 'کاب'
}
bars = request.data.get('Transports', [])
if 'Transports' in request.data:
request.data.pop('Transports')
evacuation_details = request.data.get('EvacuationDetail', [])
if 'EvacuationDetail' in request.data:
request.data.pop('EvacuationDetail')
hatching = Hatching.objects.filter(RequestCode=request.data['RequestCode']).first()
if hatching:
for key, value in request.data.items():
setattr(hatching, key, value)
hatching.save()
else:
poultry = Poultry.objects.filter(SystemCode=request.data['SystemCode']).first()
hatchings = Hatching.objects.filter(poultry=poultry).order_by('id').last()
period = hatchings.Period + 1 if hatchings else 1
request.data['Period'] = period
hatching = Hatching.objects.create(**request.data)
hatching.ArchiveDate = hatching.Date + datetime.timedelta(days=76)
if poultry:
hatching.poultry = poultry
hatching.save()
allowed_evacuation_fields = {
'PartIdCode', 'RequestId', 'MoReportId', 'ReportType', 'ReportTypeString',
'ReportDate', 'ReportDateShamsi', 'MoReason', 'MoDate', 'MoDateShamsi',
'MoStartDay', 'MoEndDay', 'MoReportSubId', 'ReportStatus', 'GoodCount',
'Message', 'ErrorCode', 'IsDeleted', 'RegDate', 'RegDateShamsi',
'RegDateShamsiWithTime', 'RegDateShamsiOnlyTime', 'ExternalId', 'StringId',
'IsPersisted', 'AllowInsert', 'AllowUpdate', 'ModalCss',
'GridContainerParametersModel', 'MenuUserAccess', 'MenuUserAccessId',
'LogTableName', 'LogTableAlias', 'PageTitle'
}
if evacuation_details:
cleaned_payload = []
external_ids = []
for evacuation_data in evacuation_details:
clean_data = {
k: v for k, v in evacuation_data.items()
if k in allowed_evacuation_fields or k == 'Id'
}
external_id = clean_data.pop('Id', None)
if external_id is not None:
clean_data['ExternalId'] = external_id
external_ids.append(external_id)
cleaned_payload.append((external_id, clean_data))
existing_map = {}
if external_ids:
existing_qs = EvacuationDetail.objects.filter(
ExternalId__in=external_ids,
)
existing_map = {ev.ExternalId: ev for ev in existing_qs}
bulk_create = []
for external_id, clean_data in cleaned_payload:
if external_id and external_id in existing_map:
evacuation = existing_map[external_id]
for key, value in clean_data.items():
setattr(evacuation, key, value)
evacuation.hatching = hatching
evacuation.save()
else:
clean_data['hatching'] = hatching
bulk_create.append(EvacuationDetail(**clean_data))
if bulk_create:
EvacuationDetail.objects.bulk_create(bulk_create)
if bars:
for transport_data in bars:
transport = TransportingDetail.objects.filter(
TrackingCode=transport_data['TrackingCode']).first()
if transport:
for key, value in transport_data.items():
setattr(transport, key, value)
transport.save()
else:
transport = TransportingDetail.objects.create(**transport_data)
kill_house = KillHouse.objects.filter(PartIdCode=transport.DesPartIdCode, trash=False).first()
transport.hatching = hatching
if kill_house:
transport.Province = kill_house.Province
transport.City = kill_house.City
if hatching.poultry.LocationIdProvince != kill_house.ProvinceId:
transport.Out = True
transport.save()
transport.Age = (transport.Date.date() - transport.hatching.Date.date()).days + 1
transport.save()
bars = TransportingDetail.objects.filter(trash=False, hatching=hatching)
bars_quantity = bars.aggregate(total=Sum('GoodAmount'))['total'] or 0
ave_age = int(bars.aggregate(avg_age=Avg('Age'))[
'avg_age'] or 0)
hatching.LeftOver = hatching.ChickCountSum - (hatching.Evacuation + bars_quantity) if (
hatching.ChickCountSum - (
hatching.Evacuation + bars_quantity)) > 0 else 0
if hatching.PedigreeName in BREED_STANDARDIZATION:
hatching.PedigreeName = BREED_STANDARDIZATION[hatching.PedigreeName]
hatching.KillingAve = ave_age
hatching.save()
return Response({"result": "با موفقیت ثبت شد"}, status=status.HTTP_201_CREATED)
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page_size = request.query_params.get('page_size')
if page_size:
self.pagination_class.page_size = int(page_size)
page = self.paginate_queryset(queryset)
if page is not None:
serializer = HatchingDetailSerializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = HatchingDetailSerializer(queryset, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
class PoultryHatchingForUpdatePedigreeNameViewSet(viewsets.ModelViewSet):
queryset = PoultryHatching.objects.all()
serializer_class = PoultryHatchingSerializer
permission_classes = [AllowAny]
def create(self, request, *args, **kwargs):
data = request.data['Data']
request.data.pop('Data')
for hatching_data in data:
hatching = PoultryHatching.objects.filter(PartIdCode=hatching_data['PartIdCode']).first()
if hatching:
if hatching.PedigreeName:
hatching.PedigreeName = 'ترکیبی'
else:
hatching.PedigreeName = hatching_data['PedigreeName']
hatching.save()
return Response({"result": "با موفقیت ثبت شد"}, status=status.HTTP_201_CREATED)
class TransportingChickenDetailViewSet(viewsets.ModelViewSet):
queryset = TransportingChickenDetail.objects.all()
serializer_class = TransportingChickenDetailSerializer
permission_classes = [AllowAny]
pagination_class = CustomPagination
filterset_class = TransportingChickenDetailFilterSet
def create(self, request, *args, **kwargs):
data = request.data['Data']
request.data.pop('Data')
for transport_data in data:
transport = TransportingChickenDetail.objects.filter(TrackingCode=transport_data['TrackingCode']).first()
if transport:
for key, value in transport_data.items():
setattr(transport, key, value)
transport.save()
else:
transport = TransportingChickenDetail.objects.create(**transport_data)
hatching = PoultryHatching.objects.filter(DesCertId=transport_data['CertId']).first()
if hatching:
transport.hatching = hatching
transport.save()
return Response({"result": "با موفقیت ثبت شد"}, status=status.HTTP_201_CREATED)
def list(self, request, *args, **kwargs):
transports = TransportingChickenDetail.objects.filter(hatching__isnull=False, trash=False).order_by(
'-issue_date')
date1 = request.GET.get('date1')
date2 = request.GET.get('date2')
if date1 and date2:
date1 = datetime.datetime.strptime(str(request.GET['date1']), '%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(request.GET['date2']), '%Y-%m-%d').date()
transports = transports.filter(reside_date__date__gte=date1, reside_date__date__lte=date2)
search = request.GET.get('search')
if search:
if search != 'undefined' and search.strip():
transports = transports.filter(
build_query(self.filterset_class.Meta.fields, search)
)
page_size = request.query_params.get('page_size', None)
if page_size:
self.pagination_class.page_size = int(page_size)
page = self.paginate_queryset(transports)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.serializer_class(transports, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
class HatchingViewSet(viewsets.ModelViewSet):
queryset = PoultryHatching.objects.all()
serializer_class = HatchingSerializer
permission_classes = [AllowAny]
pagination_class = CustomPagination
def list(self, request, *args, **kwargs):
hatchings = PoultryHatching.objects.filter(trash=False)
city = request.GET.get('city')
province = request.GET.get('province')
age = request.GET.get('age')
filters = {}
if age:
filters['HatchingAge__exact'] = age
if city:
filters['LocationNameCity__icontains'] = city
if province:
filters['LocationNameProvince__icontains'] = province
hatchings = hatchings.filter(**filters)
page_size = request.query_params.get('page_size', None)
if page_size:
self.pagination_class.page_size = int(page_size)
page = self.paginate_queryset(hatchings)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.serializer_class(hatchings, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
# class TransportingDashboardViewSet(viewsets.ModelViewSet):
# queryset = TransportingDetail.objects.filter(trash=False).only('id').order_by('id')
# serializer_class = TransportingSerializer
# permission_classes = [AllowAny]
# filterset_class = TransportingDetailFilterSet
#
# def list(self, request, *args, **kwargs):
# bars = self.queryset
# filters = {}
# RequestCode = request.GET.get('RequestCode')
# date1 = request.GET.get('date1')
# date2 = request.GET.get('date2')
# city = request.GET.get('city')
# search = request.GET.get('search')
# province = request.GET.get('province')
# if date1 and date2:
# date1 = datetime.datetime.strptime(str(request.GET['date1']), '%Y-%m-%d').date()
#
# date2 = datetime.datetime.strptime(str(request.GET['date2']), '%Y-%m-%d').date()
# filters['Date__date__gte'] = date1
# filters['Date_date__lte'] = date2
# if city:
# filters['City__icontains'] = city
#
# if province:
# filters['Province__icontains'] = province
#
# if RequestCode:
# filters['hatching__RequestCode'] = RequestCode
#
#
# bars = bars.filter(**filters)
#
# if search:
# if search != 'undefined' and search.strip():
# bars = bars.filter(
# build_query(self.filterset_class.Meta.fields, search)
# )
# bar_quantity = bars.aggregate(total=Sum('GoodAmount'))['total'] or 0
# total_bar_killing_age = bars.aggregate(avg_age=Avg('Age'))['avg_age'] or 0
# input_bar = bars.filter(Out=False)
# input_bar__percent = input_bar.count() / bars.count() * 100
# input_bar_quantity = input_bar.aggregate(total=Sum('GoodAmount'))['total'] or 0
# output_bar = bars.filter(Out=True)
# output_bar_quantity = output_bar.aggregate(total=Sum('GoodAmount'))['total'] or 0
# output_bar_percent = output_bar.count() / bars.count() * 100
# result = {
# "bar_count": bars.count(),
# "bar_quantity": bar_quantity,
# "total_bar_killing_age": total_bar_killing_age,
# "input_bar_count": input_bar.count(),
# "input_bar_quantity": input_bar_quantity,
# "input_bar_percent": input_bar__percent,
# "output_bar": output_bar.count(),
# "output_bar_quantity": output_bar_quantity,
# "output_bar_percent": output_bar_percent,
#
# }
# return Response(result, status=status.HTTP_200_OK)
class TransportingDashboardViewSet(viewsets.ModelViewSet):
queryset = TransportingDetail.objects.filter(trash=False)
serializer_class = TransportingSerializer
permission_classes = [AllowAny]
filterset_class = TransportingDetailFilterSet
def _apply_filters(self, queryset, request):
filters = {}
date1 = request.GET.get('date1')
date2 = request.GET.get('date2')
if date1 and date2:
try:
date1 = datetime.datetime.strptime(date1, '%Y-%m-%d').date()
date2 = datetime.datetime.strptime(date2, '%Y-%m-%d').date()
filters['Date__date__range'] = [date1, date2]
except ValueError:
pass
if city := request.GET.get('city'):
filters['City__icontains'] = city
if province := request.GET.get('province'):
if province == 'undefined':
province = None
filters['hatching__poultry__Province__icontains'] = province
if RequestCode := request.GET.get('RequestCode'):
filters['hatching__RequestCode'] = RequestCode
if DesPartIdCode := request.GET.get('PartIdCode'):
filters['DesPartIdCode'] = DesPartIdCode
queryset = queryset.filter(**filters)
if search := request.GET.get('search'):
if search != 'undefined' and search.strip():
queryset = queryset.filter(
build_query(self.filterset_class.Meta.fields, search)
)
return queryset
def _apply_filters_all_products(self, queryset, request):
date1 = request.GET.get('date1')
date2 = request.GET.get('date2')
if date1 and date2:
try:
date1 = datetime.datetime.strptime(date1, '%Y-%m-%d').date()
date2 = datetime.datetime.strptime(date2, '%Y-%m-%d').date()
queryset = queryset.filter(
date__gte=date1,
date__lte=date2,
date__isnull=False
)
except ValueError:
pass
if city := request.GET.get('city'):
queryset = queryset.filter(destination_city__icontains=city)
if province := request.GET.get('province'):
if province == 'undefined':
province = None
if province:
queryset = queryset.filter(destination_province__icontains=province)
if RequestCode := request.GET.get('RequestCode'):
queryset = queryset.filter(hatching__RequestCode=RequestCode)
if DesPartIdCode := request.GET.get('PartIdCode'):
queryset = queryset.filter(jihadi_destination=DesPartIdCode)
if search := request.GET.get('search'):
if search != 'undefined' and search.strip():
queryset = queryset.filter(
build_query(AllProductsTransportFilterSet.Meta.fields, search)
)
return queryset
def _calculate_metrics(self, queryset, all_products_queryset):
stats = queryset.aggregate(
total_count=Count('id'),
total_quantity=Sum('GoodAmount'),
avg_age=Avg('Age'),
input_count=Count('id', filter=Q(Out=False)),
input_quantity=Sum('GoodAmount', filter=Q(Out=False)),
output_count=Count('id', filter=Q(Out=True)),
output_quantity=Sum('GoodAmount', filter=Q(Out=True)),
)
all_products_stats = all_products_queryset.aggregate(
total_count=Count('id'),
total_quantity=Sum('quantity'),
input_count=Count('id', filter=Q(out=False)),
input_quantity=Sum('quantity', filter=Q(out=False)),
output_count=Count('id', filter=Q(out=True)),
output_quantity=Sum('quantity', filter=Q(out=True)),
)
stats['total_count'] = (stats.get('total_count') or 0) + (all_products_stats.get('total_count') or 0)
stats['total_quantity'] = (stats.get('total_quantity') or 0) + (all_products_stats.get('total_quantity') or 0)
stats['input_count'] = (stats.get('input_count') or 0) + (all_products_stats.get('input_count') or 0)
stats['input_quantity'] = (stats.get('input_quantity') or 0) + (all_products_stats.get('input_quantity') or 0)
stats['output_count'] = (stats.get('output_count') or 0) + (all_products_stats.get('output_count') or 0)
stats['output_quantity'] = (stats.get('output_quantity') or 0) + (all_products_stats.get('output_quantity') or 0)
total_count = stats['total_count'] or 1
stats.update({
'input_percent': (stats['input_count'] / total_count) * 100,
'output_percent': (stats['output_count'] / total_count) * 100,
})
return stats
def list(self, request, *args, **kwargs):
try:
filtered_bars = self._apply_filters(self.queryset, request)
query_all_products = AllProductsTransport.objects.filter(
trash=False,
product='مرغ زنده -جهت كشتار'
)
filtered_all_products = self._apply_filters_all_products(query_all_products, request)
metrics = self._calculate_metrics(filtered_bars, filtered_all_products)
result = {
"bar_count": metrics['total_count'],
"bar_quantity": metrics['total_quantity'] or 0,
"total_bar_killing_age": metrics['avg_age'] or 0,
"input_bar_count": metrics['input_count'],
"input_bar_quantity": metrics['input_quantity'] or 0,
"input_bar_percent": round(metrics['input_percent'], 2),
"output_bar": metrics['output_count'],
"output_bar_quantity": metrics['output_quantity'] or 0,
"output_bar_percent": round(metrics['output_percent'], 2),
}
return Response(result, status=status.HTTP_200_OK)
except Exception as e:
return Response(
{"error": str(e)},
status=status.HTTP_500_INTERNAL_SERVER_ERROR
)
class TransportingDetailViewSet(viewsets.ModelViewSet):
queryset = TransportingDetail.objects.filter(trash=False)
serializer_class = TransportingDetailSerializer
permission_classes = [AllowAny]
pagination_class = CustomPagination
filterset_class = TransportingDetailFilterSet
def list(self, request, *args, **kwargs):
filters = {}
PartIdCode = request.GET.get('PartIdCode')
RequestCode = request.GET.get('RequestCode')
date1 = request.GET.get('date1')
date2 = request.GET.get('date2')
city = request.GET.get('city')
province = request.GET.get('province')
if province == 'undefined':
province = None
if date1 and date2:
date1 = datetime.datetime.strptime(str(request.GET['date1']), '%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(request.GET['date2']), '%Y-%m-%d').date()
filters['Date__date__gte'] = date1
filters['Date__date__lte'] = date2
if city:
filters['City__icontains'] = city
if province:
# filters['Province__icontains'] = province
filters['hatching__poultry__Province__icontains'] = province
if PartIdCode:
filters['DesPartIdCode'] = PartIdCode
if RequestCode:
filters['hatching__RequestCode'] = RequestCode
search = request.GET.get('search')
transports = TransportingDetail.objects.filter(**filters, trash=False).order_by("-Date")
# Query برای AllProductsTransport با product='مرغ زنده -جهت كشتار'
query_all_products = AllProductsTransport.objects.filter(
trash=False,
product='مرغ زنده -جهت كشتار'
)
# اعمال فیلترها روی AllProductsTransport
if PartIdCode:
query_all_products = query_all_products.filter(jihadi_destination=PartIdCode)
if RequestCode:
query_all_products = query_all_products.filter(hatching__RequestCode=RequestCode)
if date1 and date2:
query_all_products = query_all_products.filter(
date__gte=date1,
date__lte=date2,
date__isnull=False
)
if city:
query_all_products = query_all_products.filter(destination_city__icontains=city)
if province:
query_all_products = query_all_products.filter(destination_province__icontains=province)
if search:
if search != 'undefined' and search.strip():
transports = transports.filter(
build_query(self.filterset_class.Meta.fields, search)
)
# اعمال search روی AllProductsTransport
query_all_products = query_all_products.filter(
build_query(AllProductsTransportFilterSet.Meta.fields, search)
)
# تبدیل به list و ترکیب
transports_list = list(transports)
all_products_list = list(query_all_products)
# تبدیل AllProductsTransport به TransportingDetail-like objects برای sort
def get_sort_date(obj):
if hasattr(obj, 'Date') and obj.Date:
if isinstance(obj.Date, datetime.datetime):
return obj.Date.date()
elif isinstance(obj.Date, datetime.date):
return obj.Date
elif hasattr(obj, 'date') and obj.date:
return obj.date
elif hasattr(obj, 'unloading_date') and obj.unloading_date:
return obj.unloading_date
return datetime.date.min
combined_list = []
for obj in transports_list:
combined_list.append((get_sort_date(obj), 'transporting', obj))
for obj in all_products_list:
combined_list.append((get_sort_date(obj), 'all_products', obj))
combined_list.sort(key=lambda x: x[0], reverse=True)
sorted_objects = [obj for _, _, obj in combined_list]
page_size = request.query_params.get('page_size', None)
if page_size:
self.pagination_class.page_size = int(page_size)
paginator = self.pagination_class()
page = paginator.paginate_queryset(sorted_objects, request)
if page is not None:
serialized_data = []
for obj in page:
if hasattr(obj, 'Date'): # TransportingDetail
serializer = TransportingDetailSerializer(obj, context={'request': request})
serialized_data.append(serializer.data)
else: # AllProductsTransport
serializer = AllProductsTransportSerializer(obj, context={'request': request})
data = serializer.data
date_value = obj.date if obj.date else obj.unloading_date
if date_value:
data['Date'] = datetime.datetime.combine(date_value, datetime.time.min) if isinstance(date_value, datetime.date) else date_value
else:
data['Date'] = None
data['DesPartIdCode'] = obj.jihadi_destination
data['TrackingCode'] = obj.tracking
data['GoodAmount'] = obj.quantity
data['DesUnitName'] = obj.destination
data['Province'] = obj.destination_province
data['City'] = obj.destination_city
data['Out'] = obj.out
serialized_data.append(data)
return paginator.get_paginated_response(serialized_data)
serialized_data = []
for obj in sorted_objects:
if hasattr(obj, 'Date'): # TransportingDetail
serializer = TransportingDetailSerializer(obj, context={'request': request})
serialized_data.append(serializer.data)
else: # AllProductsTransport
serializer = AllProductsTransportSerializer(obj, context={'request': request})
data = serializer.data
date_value = obj.date if obj.date else obj.unloading_date
if date_value:
data['Date'] = datetime.datetime.combine(date_value, datetime.time.min) if isinstance(date_value, datetime.date) else date_value
else:
data['Date'] = None
data['DesPartIdCode'] = obj.jihadi_destination
data['TrackingCode'] = obj.tracking
data['GoodAmount'] = obj.quantity
data['DesUnitName'] = obj.destination
data['Province'] = obj.destination_province
data['City'] = obj.destination_city
data['Out'] = obj.out
serialized_data.append(data)
return Response(serialized_data, status=status.HTTP_200_OK)
class HatchingCalculationsViewSet(viewsets.ModelViewSet):
queryset = PoultryHatching.objects.all()
serializer_class = HatchingCalculationSerializer
permission_classes = [AllowAny]
filterset_class = HatchingCalculationsFilterSet
def list(self, request, *args, **kwargs):
city = request.GET.get('city')
province = request.GET.get('province')
value = request.GET.get('value')
filters = {'trash': False}
if city:
filters['LocationNameCity__in'] = [city]
if province:
filters['LocationNameProvince__in'] = [province]
hatching_dict = PoultryHatching.objects.filter(**filters)
if value:
hatching_dict = hatching_dict.filter(
build_query(self.filterset_class.Meta.fields, value)
)
total_evacuation = build_calculation(queryset=hatching_dict, column_name='EvacuationCount', aggregate_func=Sum)
total_poultry_hatching = build_calculation(queryset=hatching_dict, column_name='HatchingCount',
aggregate_func=Sum)
total_poultry = hatching_dict.values('poultry').distinct().count()
total_leftover = build_calculation(queryset=hatching_dict, column_name='LeftOver', aggregate_func=Sum)
return Response({"evacuation_sum": total_evacuation, "hatching_count": total_poultry_hatching,
"total_poultry": total_poultry, "leftover": total_leftover
},
status=status.HTTP_200_OK)
class PoultryInfoViewSet(viewsets.ModelViewSet):
queryset = Poultry.objects.all()
serializer_class = PoultryInfoSerializer
permission_classes = [AllowAny]
pagination_class = CustomPagination
filterset_class = PoultryInfoFilterSet
def list(self, request, *args, **kwargs):
poultry = Poultry.objects.filter(trash=False).order_by('id')
search = request.GET.get('search')
leftover = request.GET.get('leftover')
province = request.GET.get('province')
city = request.GET.get('city')
if leftover:
poultry = poultry.filter(
pk__in=Hatching.objects.filter(LeftOver__gt=0, trash=False).values_list('poultry',
flat=True))
if province:
poultry = poultry.filter(LocationNameProvince__icontains=province)
if city:
poultry = poultry.filter(LocationNameCity__icontains=city)
if search:
if search != 'undefined' and search.strip():
poultry = poultry.filter(
build_query(self.filterset_class.Meta.fields, search)
)
page_size = request.query_params.get('page_size', None)
if page_size:
self.pagination_class.page_size = int(page_size)
page = self.paginate_queryset(poultry)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.serializer_class(poultry, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
class TotalKillHousesViewSet(viewsets.ModelViewSet):
queryset = KillHouse.objects.filter(trash=False).only('id', 'PartIdCode', 'UnitName', 'Province', 'City').order_by('id')
serializer_class = KillHouseSerializer
permission_classes = [AllowAny]
pagination_class = CustomPagination
filterset_class = KillHouseFilterSet
def list(self, request, *args, **kwargs):
search = request.GET.get('search')
filters = {"trash": False}
if province := request.GET.get('province'):
filters['Province'] = province
if city := request.GET.get('city'):
filters['City'] = city
if kill_houses_name := request.GET.get('name'):
filters['UnitName'] = kill_houses_name
kill_houses = self.queryset.filter(**filters)
if search:
if search != 'undefined' and search.strip():
kill_houses = kill_houses.filter(
build_query(self.filterset_class.Meta.fields, search)
)
page_size = request.query_params.get('page_size', None)
if page_size:
self.pagination_class.page_size = int(page_size)
page = self.paginate_queryset(kill_houses)
items_to_serialize = page if page is not None else kill_houses
part_id_codes = list(kill_houses.values_list('PartIdCode', flat=True).distinct())
info_cache = {}
if part_id_codes:
date1 = request.GET.get('date1') or None
date2 = request.GET.get('date2') or None
bars_query = TransportingDetail.objects.filter(
DesPartIdCode__in=part_id_codes,
trash=False
).only('DesPartIdCode', 'GoodAmount', 'Out', 'Date')
if date1:
date1_obj = datetime.datetime.strptime(str(date1), '%Y-%m-%d').date()
date2_obj = datetime.datetime.strptime(str(date2), '%Y-%m-%d').date()
bars_query = bars_query.filter(Date__date__gte=date1_obj, Date__date__lte=date2_obj)
bars_aggregations = bars_query.values('DesPartIdCode').annotate(
total=Sum('GoodAmount'),
input_total=Sum('GoodAmount', filter=Q(Out=False)),
output_total=Sum('GoodAmount', filter=Q(Out=True)),
input_count=Count('id', filter=Q(Out=False)),
output_count=Count('id', filter=Q(Out=True)),
total_count=Count('id')
)
all_products_query = AllProductsTransport.objects.filter(
jihadi_destination__in=part_id_codes,
trash=False,
product='مرغ زنده -جهت كشتار'
).only('jihadi_destination', 'quantity', 'out', 'date', 'unloading_date')
if date1:
all_products_query = all_products_query.filter(
date__gte=date1_obj,
date__lte=date2_obj,
date__isnull=False
)
all_products_aggregations = all_products_query.values('jihadi_destination').annotate(
total=Sum('quantity'),
input_total=Sum('quantity', filter=Q(out=False)),
output_total=Sum('quantity', filter=Q(out=True)),
input_count=Count('id', filter=Q(out=False)),
output_count=Count('id', filter=Q(out=True)),
total_count=Count('id')
)
bars_dict = {item['DesPartIdCode']: item for item in bars_aggregations}
all_products_dict = {item['jihadi_destination']: item for item in all_products_aggregations}
for part_id_code in part_id_codes:
bars_data = bars_dict.get(part_id_code, {})
all_products_data = all_products_dict.get(part_id_code, {})
total_count = (bars_data.get('total_count') or 0) + (all_products_data.get('total_count') or 0)
total_bars_quantity = (bars_data.get('total') or 0) + (all_products_data.get('total') or 0)
total_input_bars_quantity = (bars_data.get('input_total') or 0) + (all_products_data.get('input_total') or 0)
total_output_bars_quantity = (bars_data.get('output_total') or 0) + (all_products_data.get('output_total') or 0)
input_bars_count = (bars_data.get('input_count') or 0) + (all_products_data.get('input_count') or 0)
output_bars_count = (bars_data.get('output_count') or 0) + (all_products_data.get('output_count') or 0)
if total_count > 0:
total_input_bars_percent = round((input_bars_count / total_count) * 100, 1)
total_output_bars_percent = round((output_bars_count / total_count) * 100, 1)
else:
total_input_bars_percent = 0
total_output_bars_percent = 0
info_cache[part_id_code] = {
"bars": total_count,
"total_bars_quantity": total_bars_quantity,
"input_bars": input_bars_count,
"total_input_bars_quantity": total_input_bars_quantity,
"total_input_bars_percent": total_input_bars_percent,
"output_bars": output_bars_count,
"total_output_bars_quantity": total_output_bars_quantity,
"total_output_bars_percent": total_output_bars_percent,
}
if page is not None:
serializer = self.get_serializer(page, many=True, context={'request': request, 'info_cache': info_cache})
return self.get_paginated_response(serializer.data)
serializer = self.serializer_class(kill_houses, many=True, context={'request': request, 'info_cache': info_cache})
return Response(serializer.data, status=status.HTTP_200_OK)
class HatchingAnalysisPedigreeViewSet(viewsets.ModelViewSet):
queryset = Hatching.objects.filter(trash=False, poultry__isnull=False, PedigreeName__isnull=False)
serializer_class = HatchingAnalysisSerializer
permission_classes = [AllowAny]
def list(self, request, *args, **kwargs):
filters = {}
pedigree = request.GET.get('pedigree')
city = request.GET.get('city')
province = request.GET.get('province')
date1 = request.GET.get('date1')
date2 = request.GET.get('date2')
state = request.GET.get('state')
if date1 and date2:
date1 = datetime.datetime.strptime(str(request.GET['date1']), '%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(request.GET['date2']), '%Y-%m-%d').date()
filters['Date__date__gte'] = date1
filters['Date__date__lte'] = date2
if city:
filters['CityName__icontains'] = city
if province:
filters['ProvinceName__icontains'] = province
if pedigree:
filters['PedigreeName__icontains'] = pedigree
if state == 'active':
filters['Age__lte'] = 70
else:
pass
hatchings = self.queryset.filter(**filters)
pedigree_name_poultry = hatchings.values('PedigreeName').annotate(
poultry_count=Count('poultry', distinct=True)).order_by('-poultry_count')
pedigree_name_hatching_count = hatchings.values('PedigreeName').annotate(
chick_count=Count('ChickCountSum')).order_by(
'-chick_count')
pedigree_name_hatching_sum = hatchings.values('PedigreeName').annotate(
chick_sum=Sum('ChickCountSum')).order_by(
'-chick_sum')
pedigree_name_leftover = hatchings.values('PedigreeName').annotate(left_over=Sum('LeftOver')).order_by(
'-left_over')
pedigree_name_pedigree = hatchings.values('PedigreeName').annotate(pedigree_name=Sum('id')).order_by(
'-pedigree_name')
pedigree_name_average_age = hatchings.values(
'PedigreeName').annotate(average_age=Avg('KillingAve')).order_by('-average_age')
for item in pedigree_name_average_age:
item['average_age'] = int(item['average_age']) if item['average_age'] is not None else 0
pedigree_name_active_hatching_count = hatchings.filter(Age__lte=70).values('PedigreeName').annotate(
chick_count=Count('ChickCountSum')).order_by(
'-chick_count')
pedigree_name_active_hatching_sum = hatchings.filter(Age__lte=70).values('PedigreeName').annotate(
chick_count=Sum('ChickCountSum')).order_by(
'-chick_count')
hatchings_by_province = hatchings.values('ProvinceName', 'PedigreeName').annotate(
hatching_sum=Sum('ChickCountSum')).order_by('ProvinceName', '-hatching_sum')
provinces_dict = defaultdict(lambda: {'total_sum': 0, 'breeds': []})
for h in hatchings_by_province:
province = h['ProvinceName']
pedigree = h['PedigreeName']
hatching_sum = h['hatching_sum']
provinces_dict[province]['breeds'].append({
'pedigree': pedigree,
'hatching_sum': hatching_sum
})
provinces_dict[province]['total_sum'] += hatching_sum
province_result = [
{
'province': province,
'hatching_sum_all': values['total_sum'],
'breeds': values['breeds']
}
for province, values in provinces_dict.items()
]
pedigree_name_evacuation_sum = hatchings.values('PedigreeName').annotate(
evacuation=Sum('Evacuation')).order_by(
'-evacuation')
pedigree_name_bars_sum = hatchings.values('PedigreeName').annotate(
count_bars=Sum('transport_hatching__GoodAmount')).order_by(
'-count_bars')
evacuation_dict = {
item['PedigreeName']: item['evacuation'] or 0
for item in pedigree_name_evacuation_sum
}
hatching_dict = {
item['PedigreeName']: item['chick_sum'] or 0
for item in pedigree_name_hatching_sum
}
total_hatching = hatchings.aggregate(total=Sum('ChickCountSum'))['total'] or 1
evacuation_hatching_percent = []
for item in pedigree_name_bars_sum:
pedigree = item['PedigreeName']
evacuation_sum = evacuation_dict.get(pedigree, 0)
hatching_sum = hatching_dict.get(pedigree, 1)
percent_by_pedigree = round((evacuation_sum / hatching_sum) * 100, 2)
percent_by_total = round((evacuation_sum / total_hatching) * 100, 2)
evacuation_hatching_percent.append({
"pedigree_name": pedigree,
"pedigree": percent_by_pedigree,
"total": percent_by_total
})
result = {
"pedigree_name_poultry": pedigree_name_poultry,
"pedigree_name_hatching_count": pedigree_name_hatching_count,
"pedigree_name_hatching_sum": pedigree_name_hatching_sum,
"pedigree_name_leftover": pedigree_name_leftover,
"pedigree_name_pedigree": pedigree_name_pedigree,
"pedigree_name_average_age": pedigree_name_average_age,
"pedigree_name_active_hatching_count": pedigree_name_active_hatching_count,
"pedigree_name_active_hatching_sum": pedigree_name_active_hatching_sum,
"province_result": province_result,
"pedigree_name_evacuation_sum": pedigree_name_evacuation_sum,
"pedigree_name_bars_sum": pedigree_name_bars_sum,
"pedigree_evacuation_hatching_percent": evacuation_hatching_percent,
}
return Response(result, status=status.HTTP_200_OK)
class HatchingAnalysisProvinceView(viewsets.ModelViewSet):
queryset = Hatching.objects.filter(trash=False, poultry__isnull=False)
serializer_class = HatchingAnalysisSerializerTwo
permission_classes = [AllowAny]
def list(self, request, *args, **kwargs):
filters = {}
state = request.GET.get('state')
date1 = request.GET.get('date1')
date2 = request.GET.get('date2')
if date1 and date2:
date1 = datetime.datetime.strptime(str(request.GET['date1']), '%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(request.GET['date2']), '%Y-%m-%d').date()
filters['Date__date__gte'] = date1
filters['Date__date__lte'] = date2
if state == 'active':
filters['Age__lte'] = 70
else:
pass
hatchings = self.queryset.filter(**filters)
province_sum_transporting = hatchings.filter(transport_hatching__GoodAmount__isnull=False).values(
'ProvinceName').annotate(
good_amount=Sum('transport_hatching__GoodAmount')).order_by(
'-good_amount')
province_hatching_sum = hatchings.values('ProvinceName').annotate(
chick_sum=Sum('ChickCountSum')).order_by(
'-chick_sum')
province_name_leftover = hatchings.values('ProvinceName').annotate(left_over=Sum('LeftOver')).order_by(
'-left_over')
province_name_average_age = hatchings.values(
'ProvinceName').annotate(average_age=Avg('KillingAve')).order_by('-average_age')
province_name_poultry = hatchings.values('ProvinceName').annotate(
poultry_count=Count('poultry', distinct=True)).order_by('-poultry_count')
for item in province_name_average_age:
item['average_age'] = int(item['average_age']) if item['average_age'] is not None else 0
province_data = hatchings.values('ProvinceName').annotate(
total_evacuation=Sum('Evacuation'),
total_chicks=Sum('ChickCountSum')
).order_by('-ProvinceName')
province_evacuation_hatching_percent = []
for item in province_data:
total_chicks = item['total_chicks']
total_evacuation = item['total_evacuation']
if total_chicks:
percent = round((total_evacuation / total_chicks) * 100, 2)
else:
percent = 0
province_evacuation_hatching_percent.append({
'ProvinceName': item['ProvinceName'],
'evacuation_hatching': percent
})
result = {
"province_sum_transporting": province_sum_transporting,
"province_hatching_sum": province_hatching_sum,
"province_name_poultry": province_name_poultry,
"province_name_leftover": province_name_leftover,
"province_name_average_age": province_name_average_age,
"province_evacuation_hatching_percent": province_evacuation_hatching_percent
}
return Response(result, status=status.HTTP_200_OK)
class TransportingReportDashboardViewSet(viewsets.ModelViewSet):
queryset = TransportingDetail.objects.filter(trash=False, Province__isnull=False).select_related('hatching')
serializer_class = TransportingReportDashboard
permission_classes = [AllowAny]
def list(self, request, *args, **kwargs):
filters = {}
date1 = request.GET.get('date1')
date2 = request.GET.get('date2')
location = request.GET.get('location')
if date1 and date2:
date1 = datetime.datetime.strptime(str(request.GET['date1']), '%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(request.GET['date2']), '%Y-%m-%d').date()
filters['Date__date__gte'] = date1
filters['Date__date__lte'] = date2
transports = self.queryset.filter(**filters)
if location:
transports = transports.filter(
Q(City__icontains=location) | Q(Province__icontains=location)
)
average_age_killing = transports.aggregate(average_age=Avg('Age'))['average_age']
minimum_maximum_age_killing = transports.filter(Age__lte=70, Age__gte=0).aggregate(minimum_age=Min('Age'),
maximum_age=Max('Age'))
active_hatching = \
transports.filter(Age__lte=70, Age__gte=0).aggregate(good_count=Sum('hatching__ChickCountSum'))[
'good_count'] or 0
average_age_killing_province = transports.values(
'Province').annotate(average_age=Avg('Age')).order_by('-average_age')
for age in average_age_killing_province:
age['average_age'] = int(age['average_age']) if age['average_age'] is not None else 0
hatching_killing_province = transports.values(
'Province').annotate(
chick_sum=Sum('hatching__ChickCountSum')).order_by(
'-chick_sum')
country_hatching = transports.aggregate(
good_count=Sum('hatching__ChickCountSum')
)['good_count'] or 0
killing_name_hatching = transports.filter(DesUnitName__isnull=False).values(
'DesUnitName').annotate(
good_amount=Sum('GoodAmount')).order_by(
'-good_amount')[:15]
maximum_killing_province = transports.values(
'Province').annotate(sum_killing=Sum('GoodAmount')).order_by('-sum_killing').first()
result = {
'average_age_killing': int(average_age_killing) if average_age_killing is not None else 0,
'minimum_maximum_age_killing': minimum_maximum_age_killing,
'average_age_killing_province': average_age_killing_province,
'hatching_killing_province': hatching_killing_province,
'killing_name_hatching': killing_name_hatching,
'active_hatching': active_hatching,
'country_hatching': country_hatching,
'transport_car_count': transports.count(),
'maximum_killing_province': maximum_killing_province,
}
return Response(result, status=status.HTTP_200_OK)
class TransportingAnalysisViewSet(viewsets.ModelViewSet):
queryset = TransportingDetail.objects.filter(trash=False, Province__isnull=False)
serializer_class = TransportingSerializer
permission_classes = [AllowAny]
def list(self, request, *args, **kwargs):
qs = self.queryset
total_killing_province = qs.values('Province').annotate(total_good_amount=Sum('GoodAmount'))
total_killing_dict = {item['Province']: item['total_good_amount'] for item in total_killing_province}
total_good_amount_in_and_out = qs.values('Province', 'DesUnitName').annotate(
total_good_amount=Sum('GoodAmount')
)
total_max_amount = {}
total_min_amount = {}
max_unit_name_in_and_out = {}
min_unit_name_in_and_out = {}
for item in total_good_amount_in_and_out:
province = item['Province']
amount = item['total_good_amount']
unit_name = item['DesUnitName']
if province not in total_max_amount or amount > total_max_amount[province]:
total_max_amount[province] = amount
max_unit_name_in_and_out[province] = unit_name
if province not in total_min_amount or amount < total_min_amount[province]:
total_min_amount[province] = amount
min_unit_name_in_and_out[province] = unit_name
all_data = qs.filter(Out=True).values('Province', 'DesUnitName').annotate(
total_good_amount=Sum('GoodAmount')
)
unit_lookup = {}
for item in all_data:
province = item['Province']
unit_name = item['DesUnitName']
total_good_amount = item['total_good_amount']
if province not in unit_lookup:
unit_lookup[province] = []
unit_lookup[province].append({
'unit_name': unit_name,
'total_good_amount': total_good_amount
})
result = []
for province in total_killing_dict.keys():
out_units = unit_lookup.get(province, [])
if out_units:
max_unit = max(out_units, key=lambda x: x['total_good_amount'])
min_unit = min(out_units, key=lambda x: x['total_good_amount'])
max_unit_name = max_unit['unit_name']
max_unit_amount = max_unit['total_good_amount']
min_unit_name = min_unit['unit_name']
min_unit_amount = min_unit['total_good_amount']
else:
max_unit_name = None
max_unit_amount = 0
min_unit_name = None
min_unit_amount = 0
result.append({
"province": province,
"max_out_province_slaughterhouse": max_unit_name,
"max_out_amount": max_unit_amount,
"min_out_province_slaughterhouse": min_unit_name,
"min_out_amount": min_unit_amount,
"total_killing_province": total_killing_dict.get(province, 0),
"total_max_amount": total_max_amount.get(province, 0),
"total_min_amount": total_min_amount.get(province, 0),
"total_max_amount_unit_name": max_unit_name_in_and_out.get(province),
"total_min_amount_unit_name": min_unit_name_in_and_out.get(province),
})
return Response(result, status=status.HTTP_200_OK)
@api_view(['GET'])
@permission_classes([AllowAny])
@csrf_exempt
def get_transport_to_kill(request):
date1 = request.GET.get('date1')
date2 = request.GET.get('date2')
filters = {"trash": False}
if date1 and date2:
date1 = datetime.datetime.strptime(str(request.GET['date1']), '%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(request.GET['date2']), '%Y-%m-%d').date()
filters['issue_date__date__gte'] = date1
filters['issue_date__date__lte'] = date2
transports = TransportingChickenDetail.objects.filter(**filters)
total_amount = build_calculation(queryset=transports, column_name='GoodAmount', aggregate_func=Sum)
return Response({"total_amount": total_amount,
'len_transports': transports.count()
}, status=status.HTTP_200_OK)
@api_view(["POST"])
@permission_classes([AllowAny])
@csrf_exempt
def add_kill_house(request):
file = request.FILES['file'].read()
wb_obj = openpyxl.load_workbook(filename=BytesIO(file))
sheet = wb_obj.active
list1 = []
for i, row in enumerate(sheet.iter_rows(values_only=True)):
if i < 1 or row is None:
continue
PartIdCode = row[0]
UnitName = row[1]
City = row[2]
Province = row[3]
Province_id = row[4]
if not KillHouse.objects.filter(PartIdCode=PartIdCode, trash=False):
kill_house = KillHouse(
PartIdCode=PartIdCode,
UnitName=UnitName,
Province=Province.rstrip(),
City=City.rstrip(),
ProvinceId=Province_id
)
kill_house.save()
# print(date.date())
# for kill in kill_req:
# if kill.poultry_name == poultry and kill.quantity== quantity and \
# kill.live_weight== wieght and kill.date.date() ==date and kill.acceptor_rejector == accepterde:
# print(kill.id)
return HttpResponse(list1)
@api_view(["GET"])
@permission_classes([AllowAny])
@csrf_exempt
def update_hatching(request):
filters = {}
province = request.GET.get('province')
if province == 'ha':
filters['ProvinceName'] = 'همدان'
elif province == 'ma':
filters['ProvinceName'] = 'مرکزی'
elif province == 'ku':
filters['ProvinceName'] = 'کردستان'
else:
return Response({'result':'شهر اشتباه است'}, status=status.HTTP_403_FORBIDDEN)
hatching = Hatching.objects.filter(**filters, trash=False, Age__lte=150)
ser_data = HatchingForUpdateSerializer(hatching, many=True).data
return Response(ser_data, status=status.HTTP_200_OK)
@api_view(["GET"])
@permission_classes([AllowAny])
@csrf_exempt
def get_breeds(request):
BREED_STANDARDIZATION = {
'آربراکرز (آ<><D8A2>لاس)': 'آربراکرز (آپلاس)',
'آربراک<EFBFBD><EFBFBD>ز (آپلاس)': 'آربراکرز (آپلاس)',
'آربر<EFBFBD><EFBFBD>کرز (آپلاس)': 'آربراکرز (آپلاس)',
'را<EFBFBD><EFBFBD>': 'راس',
'ر<EFBFBD><EFBFBD>س': 'راس',
'<EFBFBD><EFBFBD>اس': 'راس',
'آ<EFBFBD><EFBFBD>ین': 'آرین',
'آر<EFBFBD><EFBFBD>ن': 'آرین',
'ایندین ریو<DB8C><D988>': 'ایندین ریور',
'ایند<EFBFBD><EFBFBD>ن ریور': 'ایندین ریور',
'ک<EFBFBD><EFBFBD>ب': 'کاب'
}
hatchings = Hatching.objects.filter(
trash=False,
PedigreeName__in=list(BREED_STANDARDIZATION.keys())
).only('id', 'PedigreeName')
updated_count = 0
for hatching in hatchings:
original_name = hatching.PedigreeName
if original_name in BREED_STANDARDIZATION:
hatching.PedigreeName = BREED_STANDARDIZATION[original_name]
hatching.save(update_fields=['PedigreeName'])
updated_count += 1
return Response({
'status': 'success',
'updated_records': updated_count,
'skipped_records': len(hatchings) - updated_count,
'message': f'Updated {updated_count} records. Skipped {len(hatchings) - updated_count}.'
})
@api_view(["GET"])
@permission_classes([AllowAny])
@csrf_exempt
def dashboard_total_kill_house(request):
filterset_class = KillHouseFilterSet
search = request.GET.get('search')
date1 = request.GET.get('date1')
date2 = request.GET.get('date2')
filters = {"trash": False}
if province := request.GET.get('province'):
filters['Province'] = province
if city := request.GET.get('city'):
filters['City'] = city
if kill_houses_name := request.GET.get('name'):
filters['UnitName'] = kill_houses_name
kill_houses = KillHouse.objects.filter(**filters).order_by('id')
if search:
if search != 'undefined' and search.strip():
kill_houses = kill_houses.filter(
build_query(filterset_class.Meta.fields, search)
)
part_id_codes = list(kill_houses.values_list('PartIdCode', flat=True))
if not part_id_codes:
return Response({
"killHouseCount": 0,
"bars": 0,
"total_bars_quantity": 0,
"total_bars_output_count": 0,
"total_bars_input_count": 0,
"total_input_bars_quantity": 0,
"total_output_bars_quantity": 0,
"top_kill_house_name": None,
"top_kill_house_amount": None,
"low_kill_house_name": None,
"low_kill_house_amount": None,
})
# بهینه‌سازی: استفاده از only() برای کاهش داده‌های خوانده شده
bars = TransportingDetail.objects.filter(DesPartIdCode__in=part_id_codes, trash=False).only('DesPartIdCode', 'GoodAmount', 'Out', 'Date')
all_products_transport = AllProductsTransport.objects.filter(
jihadi_destination__in=part_id_codes,
trash=False,
product='مرغ زنده -جهت كشتار'
).only('jihadi_destination', 'quantity', 'out', 'date', 'unloading_date')
if date1:
date1 = datetime.datetime.strptime(str(date1), '%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(date2), '%Y-%m-%d').date()
bars = bars.filter(Date__date__gte=date1, Date__date__lte=date2)
all_products_transport = all_products_transport.filter(
date__gte=date1,
date__lte=date2,
date__isnull=False
)
# بهینه‌سازی: ترکیب aggregation ها در یک query
kill_house_stats_bars = bars.values('DesPartIdCode').annotate(
total_amount=Sum('GoodAmount')
)
kill_house_stats_all_products = all_products_transport.values('jihadi_destination').annotate(
total_amount=Sum('quantity')
)
# بهینه‌سازی: استفاده از dictionary comprehension
stats_dict = {stat['DesPartIdCode']: (stat['total_amount'] or 0) for stat in kill_house_stats_bars}
for stat in kill_house_stats_all_products:
part_id = stat['jihadi_destination']
stats_dict[part_id] = stats_dict.get(part_id, 0) + (stat['total_amount'] or 0)
kill_house_stats = [
{'DesPartIdCode': k, 'total_amount': v}
for k, v in sorted(stats_dict.items(), key=lambda x: x[1], reverse=True)
]
top_kill_house_info = None
low_kill_house_info = None
if kill_house_stats:
top_stat = kill_house_stats[0]
low_stat = kill_house_stats[-1]
# بهینه‌سازی: یک query برای هر دو kill house
kill_house_part_ids = [top_stat['DesPartIdCode'], low_stat['DesPartIdCode']]
kill_houses_dict = {kh.PartIdCode: kh for kh in KillHouse.objects.filter(PartIdCode__in=kill_house_part_ids).only('PartIdCode', 'UnitName')}
top_kill_house = kill_houses_dict.get(top_stat['DesPartIdCode'])
low_kill_house = kill_houses_dict.get(low_stat['DesPartIdCode'])
if top_kill_house:
top_kill_house_info = {
"name": top_kill_house.UnitName,
"amount": top_stat['total_amount']
}
if low_kill_house:
low_kill_house_info = {
"name": low_kill_house.UnitName,
"amount": low_stat['total_amount']
}
aggregation_bars = bars.aggregate(
total=Sum('GoodAmount'),
input_total=Sum('GoodAmount', filter=Q(Out=False)),
output_total=Sum('GoodAmount', filter=Q(Out=True)),
input_count=Count('id', filter=Q(Out=False)),
output_count=Count('id', filter=Q(Out=True)),
total_count=Count('id')
)
aggregation_all_products = all_products_transport.aggregate(
total=Sum('quantity'),
input_total=Sum('quantity', filter=Q(out=False)),
output_total=Sum('quantity', filter=Q(out=True)),
input_count=Count('id', filter=Q(out=False)),
output_count=Count('id', filter=Q(out=True)),
total_count=Count('id')
)
total_count = (aggregation_bars['total_count'] or 0) + (aggregation_all_products['total_count'] or 0)
total_bars_quantity = (aggregation_bars['total'] or 0) + (aggregation_all_products['total'] or 0)
total_input_bars_quantity = (aggregation_bars['input_total'] or 0) + (aggregation_all_products['input_total'] or 0)
total_output_bars_quantity = (aggregation_bars['output_total'] or 0) + (aggregation_all_products['output_total'] or 0)
input_count = (aggregation_bars['input_count'] or 0) + (aggregation_all_products['input_count'] or 0)
output_count = (aggregation_bars['output_count'] or 0) + (aggregation_all_products['output_count'] or 0)
return Response({
"killHouseCount": len(part_id_codes),
"bars": total_count,
"total_bars_quantity": total_bars_quantity,
"total_bars_output_count": output_count,
"total_bars_input_count": input_count,
"total_input_bars_quantity": total_input_bars_quantity,
"total_output_bars_quantity": total_output_bars_quantity,
"top_kill_house_name": top_kill_house_info.get('name') if top_kill_house_info else None,
"top_kill_house_amount": top_kill_house_info.get('amount') if top_kill_house_info else None,
"low_kill_house_name": low_kill_house_info.get('name') if low_kill_house_info else None,
"low_kill_house_amount": low_kill_house_info.get('amount') if low_kill_house_info else None,
})
class HatchingAnalysisOverviewViewSet(viewsets.ModelViewSet):
queryset = Hatching.objects.filter(trash=False, poultry__isnull=False, PedigreeName__isnull=False,
)
serializer_class = HatchingAnalysisSerializer
permission_classes = [AllowAny]
def list(self, request, *args, **kwargs):
filters = {}
pedigree = request.GET.get('pedigree')
city = request.GET.get('city')
province = request.GET.get('province')
date1 = request.GET.get('date1')
date2 = request.GET.get('date2')
state = request.GET.get('state')
if date1 and date2:
date1 = datetime.datetime.strptime(str(request.GET['date1']), '%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(request.GET['date2']), '%Y-%m-%d').date()
filters['Date__date__gte'] = date1
filters['Date__date__lte'] = date2
if city:
filters['CityName__icontains'] = city
if province:
filters['ProvinceName__icontains'] = province
if pedigree:
filters['PedigreeName__icontains'] = pedigree
if state == 'active':
filters['Age__lte'] = 70
hatchings = self.queryset.filter(**filters)
kill_houses_overview = hatchings.filter(transport_hatching__DesUnitName__isnull=False).values(
'transport_hatching__DesUnitName', 'PedigreeName'
).annotate(
total_amount=Sum('transport_hatching__GoodAmount')
).order_by('-total_amount')
hatching_total_poultry_overview = hatchings.filter(poultry__UnitName__isnull=False).values('poultry__UnitName',
'PedigreeName').annotate(
chick_count=Sum('ChickCountSum')
).order_by('-chick_count')
evacuation_total_poultry_overview = hatchings.filter(poultry__UnitName__isnull=False).values(
'poultry__UnitName', 'PedigreeName').annotate(
evacuation=Sum('Evacuation')
).order_by('-evacuation')
kill_house_total = defaultdict(int)
kill_house_total_pedigrees = defaultdict(list)
hatching_total = defaultdict(int)
hatching_total_pedigrees = defaultdict(list)
evacuation_total = defaultdict(int)
evacuation_total_pedigrees = defaultdict(list)
for item in kill_houses_overview:
kill_house_name = item['transport_hatching__DesUnitName']
pedigree_name = item['PedigreeName']
total_amount = item['total_amount'] or 0
kill_house_total[kill_house_name] += total_amount
kill_house_total_pedigrees[kill_house_name].append({pedigree_name: total_amount})
max_kill_house_name = max(kill_house_total, key=kill_house_total.get)
min_kill_house_name = min(kill_house_total, key=kill_house_total.get)
for data in hatching_total_poultry_overview:
poultry_unit_name = data['poultry__UnitName']
pedigree_name = data['PedigreeName']
chick_count_sum = data['chick_count'] or 0
hatching_total[poultry_unit_name] += chick_count_sum
hatching_total_pedigrees[poultry_unit_name].append({pedigree_name: chick_count_sum})
max_poultry_unit_name = max(hatching_total, key=hatching_total.get)
min_poultry_unit_name = min(hatching_total, key=hatching_total.get)
for info in evacuation_total_poultry_overview:
poultry_unit_name = info['poultry__UnitName']
pedigree_name = info['PedigreeName']
evacuation_sum = info['evacuation'] or 0
evacuation_total[poultry_unit_name] += evacuation_sum
evacuation_total_pedigrees[poultry_unit_name].append({pedigree_name: evacuation_sum})
max_evacuation_total_poultry = max(evacuation_total, key=evacuation_total.get)
min_evacuation_total_poultry = min(evacuation_total, key=evacuation_total.get)
overview = {
"kill_house": {
"max": {
"name": max_kill_house_name,
"total_amount": kill_house_total[max_kill_house_name],
"pedigrees": kill_house_total_pedigrees[max_kill_house_name]
},
"min": {
"name": min_kill_house_name,
"total_amount": kill_house_total[min_kill_house_name],
"pedigrees": kill_house_total_pedigrees[min_kill_house_name]
}
},
"hatching_poultry": {
"max": {
"name": max_poultry_unit_name,
"total_chick_count": hatching_total[max_poultry_unit_name],
"pedigrees": hatching_total_pedigrees[max_poultry_unit_name]
},
"min": {
"name": min_poultry_unit_name,
"total_chick_count": hatching_total[min_poultry_unit_name],
"pedigrees": hatching_total_pedigrees[min_poultry_unit_name]
}
},
"evacuation_poultry": {
"max": {
"name": max_evacuation_total_poultry,
"total_evacuation": evacuation_total[max_evacuation_total_poultry],
"pedigrees": evacuation_total_pedigrees[max_evacuation_total_poultry]
},
"min": {
"name": min_evacuation_total_poultry,
"total_evacuation": evacuation_total[min_evacuation_total_poultry],
"pedigrees": evacuation_total_pedigrees[min_evacuation_total_poultry]
}
}
}
result = {
"overview": overview
}
return Response(result, status=status.HTTP_200_OK)
class TransportingDetailCustomViewSet(viewsets.ModelViewSet):
queryset = TransportingDetail.objects.filter(trash=False)
serializer_class = TransportingDetailSerializer
permission_classes = [AllowAny]
pagination_class = CustomPagination
filterset_class = TransportingDetailCustomFilterSet
def list(self, request, *args, **kwargs):
transports = self.filter_queryset(self.get_queryset())
search = request.GET.get('search')
if search:
if search != 'undefined' and search.strip():
transports = transports.filter(
build_query(self.filterset_class.Meta.fields, search)
)
page_size = request.query_params.get('page_size', None)
if page_size:
self.pagination_class.page_size = int(page_size)
page = self.paginate_queryset(transports)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.serializer_class(transports, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
@api_view(['POST'])
@permission_classes([AllowAny])
@csrf_exempt
def send_different_bar(request):
filters = {'trash': False}
filters_province = {'trash': False}
filters_bar = {'trash': False}
province = request.GET.get('province')
if province:
if province == 'ha':
filters['poultry__LocationNameProvince'] = 'همدان'
filters_province['poultry__Province'] = 'همدان'
elif province == 'ma':
filters['poultry__LocationNameProvince'] = 'مرکزی'
filters_province['poultry__Province'] = 'مرکزی'
elif province == 'ku':
filters['poultry__LocationNameProvince'] = 'کردستان'
filters_province['poultry__Province'] = 'کردستان'
else:
filters['poultry__LocationNameProvince'] = 'بوشهر'
filters_province['poultry__Province'] = 'بوشهر'
if request.GET.get('date1') != 'None':
date1 = datetime.datetime.strptime(str(request.GET['date1']),
'%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(request.GET['date2']),
'%Y-%m-%d').date()
filters_bar['Date__date__gte'] = date1
filters_bar['Date__date__lte'] = date2
poultry = Hatching.objects.filter(Q(**filters) | Q(**filters_province))
bar = TransportingDetail.objects.filter(**filters_bar, hatching__in=poultry, TrackingStatusDescription__in=(
'تایید تخلیه', 'بارگیری'
)).exclude(
TrackingCode__in=request.data
).order_by('-Date')
quarantine_code = bar.values_list('TrackingCode', flat=True).distinct()
bar = bar.filter(TrackingCode__in=quarantine_code).order_by('-Date')
ser_data = TransportingForClearanceCodeSerializer(bar, many=True).data
return Response(ser_data)
class ApiSendDifferentBar(viewsets.ModelViewSet):
queryset = TransportingDetail.objects.filter(trash=False)
serializer_class = TransportingForClearanceCodeSerializer
permission_classes = [AllowAny]
pagination_class = CustomPagination
filterset_class = TransportingDetailFilterSet
def list(self, request, *args, **kwargs):
filters = {'trash': False}
filters_bar = {'trash': False}
province = request.GET.get('province')
if province == 'ha':
filters['poultry__LocationNameProvince'] = 'همدان'
elif province == 'ma':
filters['poultry__LocationNameProvince'] = 'مرکزی'
elif province == 'ku':
filters['poultry__LocationNameProvince'] = 'کردستان'
else:
filters['poultry__LocationNameProvince'] = 'بوشهر'
if request.GET.get('date1') != 'None':
date1 = datetime.datetime.strptime(str(request.GET['date1']),
'%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(request.GET['date2']),
'%Y-%m-%d').date()
filters_bar['Date__date__gte'] = date1
filters_bar['Date__date__lte'] = date2
poultry = Hatching.objects.filter(**filters)
bar = TransportingDetail.objects.filter(**filters_bar, hatching__in=poultry, TrackingStatusDescription__in=(
'تایید تخلیه', 'بارگیری'
)).exclude(
TrackingCode__in=request.data
).order_by('-Date')
quarantine_code = bar.values_list('TrackingCode', flat=True).distinct()
bar = bar.filter(TrackingCode__in=quarantine_code).order_by('-Date')
search = request.GET.get('search')
value = request.GET.get('value')
if search:
if search != 'undefined' and value.strip():
bar = bar.filter(
build_query(self.filterset_class.Meta.fields, value)
)
page_size = request.query_params.get('page_size', None)
if page_size:
self.pagination_class.page_size = int(page_size)
page = self.paginate_queryset(bar)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
ser_data = TransportingForClearanceCodeSerializer(bar, many=True).data
return Response(ser_data)
class ApkInfoViewSet(viewsets.ModelViewSet):
queryset = ApkInfo.objects.filter(trash=False)
serializer_class = ApkInfoSerializer
permission_classes = [AllowAny]
def get_object(self):
return self.queryset.first()
def list(self, request, *args, **kwargs):
instance = ApkInfo.objects.filter(trash=False).first()
serializer = self.serializer_class(instance)
return Response(serializer.data, status=status.HTTP_200_OK)
def update(self, request, *args, **kwargs):
instance = ApkInfo.objects.filter(trash=False).first()
serializer = self.serializer_class(instance, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
RASADYAR_ENDPOINT = 'https://s3.rasadyar.com'
RASADYAR_BUCKET_NAME = 'rasadyar'
RASADYAR_ACCESS_KEY = "zG3ewsbYsTqCmuws"
RASADYAR_SECRET_KEY = 'RInUMB78zlQZp6CNf8+sRoSh2cNDHcGQhXrLnTJ1AuI='
def upload_to_liara(image, name):
s3 = boto3.client(
's3',
endpoint_url=RASADYAR_ENDPOINT,
aws_access_key_id=RASADYAR_ACCESS_KEY,
aws_secret_access_key=RASADYAR_SECRET_KEY
)
s3.upload_fileobj(
image,
RASADYAR_BUCKET_NAME,
name,
ExtraArgs={'ACL': 'public-read'}
)
return f"{RASADYAR_ENDPOINT}/{RASADYAR_BUCKET_NAME}/{name}"
class RasadyarAppInfoViewSet(viewsets.ModelViewSet):
queryset = RasadyarAppInfo.objects.filter(trash=False)
serializer_class = RasadyarAppInfoSerializer
permission_classes = [AllowAny]
def get_object(self):
return self.queryset.first()
def list(self, request, *args, **kwargs):
instance = RasadyarAppInfo.objects.filter(trash=False).first()
if not instance:
instance = RasadyarAppInfo.objects.create()
serializer = self.serializer_class(instance)
return Response(serializer.data, status=status.HTTP_200_OK)
def create(self, request, *args, **kwargs):
instance = RasadyarAppInfo.objects.filter(trash=False).first()
if not instance:
instance = RasadyarAppInfo()
if 'file' in request.FILES:
ran = ''.join(random.choices(string.ascii_uppercase + string.digits, k=15))
file_obj = request.FILES.get('file')
file_name = file_obj.name
file_extension = file_name.split('.')[-1] if '.' in file_name else ''
file_name = f"{ran}.{file_extension}"
file_url = upload_to_liara(file_obj, file_name)
instance.file = file_url
if 'info' in request.data:
info_data = request.data.get('info')
if isinstance(info_data, str):
try:
instance.info = json.loads(info_data)
except json.JSONDecodeError:
instance.info = info_data
else:
instance.info = info_data
instance.save()
serializer = self.serializer_class(instance)
return Response(serializer.data, status=status.HTTP_201_CREATED)
def update(self, request, *args, **kwargs):
instance = RasadyarAppInfo.objects.filter(trash=False).first()
if not instance:
instance = RasadyarAppInfo()
if 'file' in request.FILES:
uploaded_file = request.FILES['file']
file_extension = uploaded_file.name.split('.')[-1] if '.' in uploaded_file.name else ''
unique_filename = f"rasadyar_app_info_{uuid.uuid4().hex}.{file_extension}" if file_extension else f"rasadyar_app_info_{uuid.uuid4().hex}"
file_url = upload_to_liara(uploaded_file, unique_filename)
instance.file = file_url
if 'info' in request.data:
info_data = request.data.get('info')
if isinstance(info_data, str):
try:
instance.info = json.loads(info_data)
except json.JSONDecodeError:
instance.info = info_data
else:
instance.info = info_data
instance.save()
serializer = self.serializer_class(instance)
return Response(serializer.data, status=status.HTTP_200_OK)
@api_view(['POST'])
@permission_classes([AllowAny])
@csrf_exempt
def send_different_bar_with_licence_number(request):
filters_bar = {'trash': False}
if request.GET.get('date1') != 'None':
date1 = datetime.datetime.strptime(str(request.GET['date1']),
'%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(request.GET['date2']),
'%Y-%m-%d').date()
filters_bar['Date__date__gte'] = date1
filters_bar['Date__date__lte'] = date2
hatching = Hatching.objects.filter(RequestCode=request.GET['licence_number'])
bar = TransportingDetail.objects.filter(**filters_bar, hatching__in=hatching, TrackingStatusDescription__in=(
'تایید تخلیه', 'بارگیری'
)).order_by('-Date')
ser_data = TransportingForClearanceCodeSerializer(bar, many=True).data
return Response(ser_data)
class TransportCarcassDetailViewSet(viewsets.ModelViewSet):
queryset = TransportCarcassDetail.objects.filter(trash=False)
serializer_class = TransportCarcassDetailSerializer
permission_classes = [AllowAny]
pagination_class = CustomPagination
filterset_class = TransportCarcassDetailFilterSet
def list(self, request, *args, **kwargs):
search = request.GET.get('search')
type_role = request.GET.get('role')
province = request.GET.get('province')
if province == 'undefined':
province = None
if 'code' in request.GET:
date1 = request.GET.get('date1')
code = request.GET.get('code')
filters={}
# Query برای TransportCarcassDetail
query_carcass = self.queryset.filter(jihadi_origin=code)
# Query برای AllProductsTransport با product='گوشت مرغ تازه'
query_all_products = AllProductsTransport.objects.filter(
trash=False,
product='گوشت مرغ تازه',
jihadi_origin=code
)
if date1:
date1 = datetime.datetime.strptime(str(request.GET['date1']),
'%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(request.GET['date2']),
'%Y-%m-%d').date()
query_carcass = query_carcass.filter(
Q(
product_date__gte=date1,
product_date__lte=date2,
product_date__isnull=False
) |
Q(
date__gte=date1,
date__lte=date2,
product_date__isnull=True
)
)
query_all_products = query_all_products.filter(
date__gte=date1,
date__lte=date2,
date__isnull=False
)
if search:
if search != 'undefined' and search.strip():
query_carcass = query_carcass.filter(
build_query(self.filterset_class.Meta.fields, search)
)
# اعمال search روی AllProductsTransport
query_all_products = query_all_products.filter(
build_query(AllProductsTransportFilterSet.Meta.fields, search)
)
# تبدیل به list و ترکیب
carcass_list = list(query_carcass)
all_products_list = list(query_all_products)
# تبدیل AllProductsTransport به TransportCarcassDetail-like objects برای sort
def get_sort_date(obj):
if hasattr(obj, 'product_date') and obj.product_date:
return obj.product_date
elif hasattr(obj, 'date') and obj.date:
return obj.date
elif hasattr(obj, 'unloading_date') and obj.unloading_date:
return obj.unloading_date
return datetime.date.min
# ایجاد یک list ترکیبی با tuple (date, source_type, obj)
combined_list = []
for obj in carcass_list:
combined_list.append((get_sort_date(obj), 'carcass', obj))
for obj in all_products_list:
combined_list.append((get_sort_date(obj), 'all_products', obj))
# sort بر اساس date (از جدید به قدیم)
combined_list.sort(key=lambda x: x[0], reverse=True)
# جدا کردن objects
sorted_objects = [obj for _, _, obj in combined_list]
page_size = request.query_params.get('page_size', None)
if page_size:
self.pagination_class.page_size = int(page_size)
# Pagination روی list
paginator = self.pagination_class()
page = paginator.paginate_queryset(sorted_objects, request)
if page is not None:
# Serialize هر object با serializer مناسب
serialized_data = []
for obj in page:
if hasattr(obj, 'product_date'): # TransportCarcassDetail
serializer = TransportCarcassDetailSerializer(obj, context={'request': request})
serialized_data.append(serializer.data)
else: # AllProductsTransport
# تبدیل به dict و اضافه کردن فیلدهای مشترک
serializer = AllProductsTransportSerializer(obj, context={'request': request})
data = serializer.data
# اضافه کردن فیلدهای مشابه TransportCarcassDetail برای سازگاری
data['product_date'] = obj.date
data['id_quarantineh'] = obj.record_id
serialized_data.append(data)
return paginator.get_paginated_response(serialized_data)
# اگر pagination نبود
serialized_data = []
for obj in sorted_objects:
if hasattr(obj, 'product_date'): # TransportCarcassDetail
serializer = TransportCarcassDetailSerializer(obj, context={'request': request})
serialized_data.append(serializer.data)
else: # AllProductsTransport
serializer = AllProductsTransportSerializer(obj, context={'request': request})
data = serializer.data
data['product_date'] = obj.date
data['id_quarantineh'] = obj.record_id
serialized_data.append(data)
return Response(serialized_data, status=status.HTTP_200_OK)
if type_role:
if type_role == 'KillHouse':
filters_kill_house = {}
if province:
filters_kill_house['Province'] = province
kill_house_filterset_class = KillHouseFilterSet
kill_house = KillHouse.objects.filter(**filters_kill_house).order_by('id')
if search and search != 'undefined' and search.strip():
kill_house = kill_house.filter(
build_query(kill_house_filterset_class.Meta.fields, search)
)
date1 = request.GET.get('date1')
date2 = request.GET.get('date2')
bars = TransportCarcassDetail.objects.filter(trash=False)
buy_bars = TransportingDetail.objects.filter(trash=False, Date__date__gte='2025-03-21',
TrackingStatusDescription__in=("تایید تخلیه",'بارگیری'))
all_products_transport_carcass = AllProductsTransport.objects.filter(trash=False, product='گوشت مرغ تازه',jihadi_origin__in=kill_house.values_list('PartIdCode', flat=True))
all_products_transport = AllProductsTransport.objects.filter(trash=False, product='مرغ زنده -جهت كشتار',jihadi_destination__in=kill_house.values_list('PartIdCode', flat=True))
if date1:
date1 = datetime.datetime.strptime(str(date1), '%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(date2), '%Y-%m-%d').date()
bars = bars.filter(Q(product_date__gte=date1, product_date__lte=date2, product_date__isnull=False) |
Q(date__gte=date1, date__lte=date2, product_date__isnull=True))
all_products_transport_carcass = all_products_transport_carcass.filter(
date__gte=date1, date__lte=date2, date__isnull=False
)
date_1_for_buy_bars = date1 - datetime.timedelta(days=1)
date_2_for_buy_bars = date2 - datetime.timedelta(days=1)
buy_bars = buy_bars.filter(Date__date__gte=date_1_for_buy_bars, Date__date__lte=date_2_for_buy_bars)
all_products_transport = all_products_transport.filter(
date__gte=date_1_for_buy_bars, date__lte=date_2_for_buy_bars, date__isnull=False
)
bars_summary = bars.values('jihadi_origin').annotate(
total=Sum('quantity'),
input_total=Sum('quantity', filter=Q(out=False)),
output_total=Sum('quantity', filter=Q(out=True)),
input_count=Count('id', filter=Q(out=False)),
output_count=Count('id', filter=Q(out=True)),
total_count=Count('id'),
)
all_products_transport_carcass_summary = all_products_transport_carcass.values('jihadi_origin').annotate(
total=Sum('quantity'),
input_total=Sum('quantity', filter=Q(out=False)),
output_total=Sum('quantity', filter=Q(out=True)),
input_count=Count('id', filter=Q(out=False)),
output_count=Count('id', filter=Q(out=True)),
total_count=Count('id'),
)
buy_summary = buy_bars.values('DesPartIdCode').annotate(
total=Sum('GoodAmount'),
input_total=Sum('GoodAmount', filter=Q(Out=False)),
output_total=Sum('GoodAmount', filter=Q(Out=True)),
input_count=Count('id', filter=Q(Out=False)),
output_count=Count('id', filter=Q(Out=True)),
total_count=Count('id'),
)
all_products_transport_summary = all_products_transport.values('jihadi_destination').annotate(
total=Sum('quantity'),
input_total=Sum('quantity', filter=Q(out=False)),
output_total=Sum('quantity', filter=Q(out=True)),
input_count=Count('id', filter=Q(out=False)),
output_count=Count('id', filter=Q(out=True)),
total_count=Count('id'),
)
# ادغام bars_summary و all_products_transport_carcass_summary
bars_dict = {row['jihadi_origin']: row for row in bars_summary if row.get('jihadi_origin')}
for row in all_products_transport_carcass_summary:
key = row.get('jihadi_origin')
if not key:
continue
if key in bars_dict:
bars_dict[key]['total'] = (bars_dict[key].get('total', 0) or 0) + (row.get('total', 0) or 0)
bars_dict[key]['input_total'] = (bars_dict[key].get('input_total', 0) or 0) + (row.get('input_total', 0) or 0)
bars_dict[key]['output_total'] = (bars_dict[key].get('output_total', 0) or 0) + (row.get('output_total', 0) or 0)
bars_dict[key]['input_count'] = (bars_dict[key].get('input_count', 0) or 0) + (row.get('input_count', 0) or 0)
bars_dict[key]['output_count'] = (bars_dict[key].get('output_count', 0) or 0) + (row.get('output_count', 0) or 0)
bars_dict[key]['total_count'] = (bars_dict[key].get('total_count', 0) or 0) + (row.get('total_count', 0) or 0)
else:
bars_dict[key] = row
# ادغام buy_summary و all_products_transport_summary
buy_dict = {row['DesPartIdCode']: row for row in buy_summary if row.get('DesPartIdCode')}
for row in all_products_transport_summary:
key = row.get('jihadi_destination') # jihadi_destination همان DesPartIdCode است
if not key:
continue
if key in buy_dict:
buy_dict[key]['total'] = (buy_dict[key].get('total', 0) or 0) + (row.get('total', 0) or 0)
buy_dict[key]['input_total'] = (buy_dict[key].get('input_total', 0) or 0) + (row.get('input_total', 0) or 0)
buy_dict[key]['output_total'] = (buy_dict[key].get('output_total', 0) or 0) + (row.get('output_total', 0) or 0)
buy_dict[key]['input_count'] = (buy_dict[key].get('input_count', 0) or 0) + (row.get('input_count', 0) or 0)
buy_dict[key]['output_count'] = (buy_dict[key].get('output_count', 0) or 0) + (row.get('output_count', 0) or 0)
buy_dict[key]['total_count'] = (buy_dict[key].get('total_count', 0) or 0) + (row.get('total_count', 0) or 0)
else:
# تبدیل jihadi_destination به DesPartIdCode برای سازگاری
buy_dict[key] = {
'DesPartIdCode': key,
'total': row.get('total', 0) or 0,
'input_total': row.get('input_total', 0) or 0,
'output_total': row.get('output_total', 0) or 0,
'input_count': row.get('input_count', 0) or 0,
'output_count': row.get('output_count', 0) or 0,
'total_count': row.get('total_count', 0) or 0,
}
kill_house = list(kill_house)
kill_house.sort(
key=lambda kh: (bars_dict.get(kh.PartIdCode, {}) or {}).get('total', 0) or 0,
reverse=True
)
page_size = request.query_params.get('page_size', None)
if page_size:
self.pagination_class.page_size = int(page_size)
page = self.paginate_queryset(kill_house)
if page is not None:
serializer = KillHouseForTransportCarcassSerializer(
page, many=True, context={'request': request, 'bars_dict': bars_dict, 'buy_dict': buy_dict}
)
return self.get_paginated_response(serializer.data)
serializer = KillHouseForTransportCarcassSerializer(
kill_house, many=True, context={'request': request, 'bars_dict': bars_dict, 'buy_dict': buy_dict}
)
return Response(serializer.data, status=status.HTTP_200_OK)
else:
filters_steward = {}
if province:
filters_steward['province'] = province
steward_filterset_class = GuildsFilterSet
steward = Guilds.objects.filter(**filters_steward, trash=False, is_steward=True).order_by('id')
if search and search != 'undefined' and search.strip():
steward = steward.filter(
build_query(steward_filterset_class.Meta.fields, search)
)
date1 = request.GET.get('date1')
date2 = request.GET.get('date2')
bars = TransportCarcassDetail.objects.filter(trash=False).order_by('-product_date')
if date1:
date1 = datetime.datetime.strptime(str(date1), '%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(date2), '%Y-%m-%d').date()
bars = bars.filter(product_date__gte=date1, product_date__lte=date2)
bars_summary = bars.values('jihadi_origin', 'jihadi_destination').annotate(
total=Sum('quantity', filter=Q(jihadi_origin=F('jihadi_origin'))),
input_total=Sum('quantity', filter=Q(out=False, jihadi_origin=F('jihadi_origin'))),
output_total=Sum('quantity', filter=Q(out=True, jihadi_origin=F('jihadi_origin'))),
input_count=Count('id', filter=Q(out=False, jihadi_origin=F('jihadi_origin'))),
output_count=Count('id', filter=Q(out=True, jihadi_origin=F('jihadi_origin'))),
total_count=Count('id', filter=Q(jihadi_origin=F('jihadi_origin'))),
total_input_buy_bars_wight=Sum('quantity',
filter=Q(out=False, jihadi_destination=F('jihadi_destination'))),
total_input_buy_bars_count=Count('id',
filter=Q(out=False, jihadi_destination=F('jihadi_destination'))),
total_output_buy_bars_wight=Sum('quantity',
filter=Q(out=True, jihadi_destination=F('jihadi_destination'))),
total_output_buy_bars_count=Count('id',
filter=Q(out=True, jihadi_destination=F('jihadi_destination'))),
)
bars_dict = {}
for row in bars_summary:
code = row['jihadi_origin'] or row['jihadi_destination']
if code:
bars_dict[code] = row
steward = list(steward)
steward.sort(
key=lambda s: (bars_dict.get(s.jihadi_code, {}) or {}).get('total', 0) or 0,
reverse=True
)
page_size = request.query_params.get('page_size', None)
if page_size:
self.pagination_class.page_size = int(page_size)
page = self.paginate_queryset(steward)
if page is not None:
serializer = StewardForTransportCarcassSerializer(
page, many=True, context={'request': request, 'bars_dict': bars_dict}
)
return self.get_paginated_response(serializer.data)
serializer = StewardForTransportCarcassSerializer(
steward, many=True, context={'request': request, 'bars_dict': bars_dict}
)
return Response(serializer.data, status=status.HTTP_200_OK)
return Response('ok', status=status.HTTP_200_OK)
def create(self, request, *args, **kwargs):
file = request.FILES['file'].read()
wb_obj = openpyxl.load_workbook(filename=BytesIO(file))
sheet = wb_obj.active
# گرفتن مقادیر اولیه برای چک کردن وجود داشتن
kill_house_code = set(
KillHouse.objects.only('PartIdCode').values_list('PartIdCode', flat=True)
)
steward_jihadi_code = set(
Guilds.objects.filter(trash=False, is_steward=True).values_list('jihadi_code', flat=True)
)
headers = [str(cell).strip() for cell in next(sheet.iter_rows(values_only=True))]
field_map = {
"id": "id_quarantineh",
"مقصد قبلی": "destination_prev",
"تغییر مقصد": "destination_changed",
"پرداخت": "payment",
"رهگیری": "tracking",
"تاریخ": "date",
"ساعت": "time",
"محصول": "product",
"اقلام": "items",
"مقدار": "quantity",
"واحد": "unit",
"استان مبدا": "origin_province",
"شهرستان مبدا": "origin_city",
"مبدا": "origin",
"استان مقصد": "destination_province",
"شهرستان مقصد": "destination_city",
"مقصد": "destination",
"ش جهادی مبدا": "jihadi_origin",
"ش جهادی مقصد": "jihadi_destination",
"مالک": "owner",
"کد رهگیری خودرو": "car_tracking_code",
"نام راننده": "driver_name",
"پلاک": "plate",
"مبلغ": "amount",
"تخلیه": "unloading",
"وزن پر": "gross_weight",
"وزن خالی": "tare_weight",
"وزن": "net_weight",
"کد باسکول": "scale_code",
"نام باسکول": "scale_name",
"قبض باسکول": "scale_receipt",
"تاریخ تخلیه": "unloading_date",
"Out": "out",
}
out_flag = True if request.data.get('out') == 'true' else False
bulk_guilds_create = []
bulk_records_create = []
record_updates = {}
for row in sheet.iter_rows(min_row=2, values_only=True):
if not row:
continue
row_data = dict(zip(headers, row))
tracking_val = row_data.get("رهگیری")
if not tracking_val:
continue
steward_code = row_data.get("ش جهادی مبدا")
guilds_code = row_data.get("ش جهادی مقصد")
# گیلد مبدا
if steward_code and steward_code not in kill_house_code and steward_code not in steward_jihadi_code:
bulk_guilds_create.append(Guilds(
jihadi_code=steward_code,
name=row_data.get("مبدا"),
city=row_data.get("شهرستان مبدا"),
province=row_data.get("استان مبدا"),
is_steward=True
))
steward_jihadi_code.add(steward_code)
# گیلد مقصد
if guilds_code and guilds_code not in kill_house_code and guilds_code not in steward_jihadi_code:
bulk_guilds_create.append(Guilds(
jihadi_code=guilds_code,
name=row_data.get("مقصد"),
city=row_data.get("شهرستان مقصد"),
province=row_data.get("استان مقصد"),
is_steward=False
))
steward_jihadi_code.add(guilds_code)
record_data = {}
for col_name, model_field in field_map.items():
if col_name in row_data:
value = row_data[col_name]
if model_field in ["date", "unloading_date"] and value:
try:
if isinstance(value, str):
y, m, d = map(int, value.split("/"))
value = convert_to_miladi(y, m, d)
elif hasattr(value, "year"):
value = convert_to_miladi(value.year, value.month, value.day)
except:
value = None
if model_field == "out":
record_data[model_field] = out_flag
else:
record_data[model_field] = value
record_updates[tracking_val] = record_data
# ذخیره گیلدها
if bulk_guilds_create:
Guilds.objects.bulk_create(bulk_guilds_create, ignore_conflicts=True)
# بررسی رکوردهای موجود
existing_trackings = set(
TransportCarcassDetail.objects.filter(
tracking__in=record_updates.keys()
).values_list('tracking', flat=True)
)
for tracking_val, data in record_updates.items():
data["out"] = out_flag
if tracking_val in existing_trackings:
TransportCarcassDetail.objects.filter(tracking=tracking_val).update(**data)
else:
data["tracking"] = tracking_val
bulk_records_create.append(TransportCarcassDetail(**data))
if bulk_records_create:
TransportCarcassDetail.objects.bulk_create(bulk_records_create)
return Response({'result': 'ok'}, status=status.HTTP_201_CREATED)
class DriveViewSet(viewsets.ModelViewSet):
queryset = Driver.objects.filter(trash=False)
serializer_class = DriverSerializer
permission_classes = [AllowAny]
pagination_class = CustomPagination
filterset_class = DriverFilterSet
def list(self, request, *args, **kwargs):
if 'code' in request.GET:
query = self.queryset.filter(tracking_code__regex=r'^\d{7}$').only('tracking_code').values_list('tracking_code',flat=True).distinct()
return Response({'codes':query}, status=status.HTTP_200_OK)
if 'all' in request.GET:
query = self.queryset.filter(tracking_code__regex=r'^\d{7}$',trash=False,pelak__isnull=False).order_by('part_id_code')
serializer = self.serializer_class(query, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
filters = {}
date1 = request.GET.get('date1')
date2 = request.GET.get('date2')
city = request.GET.get('city')
province = request.GET.get('province')
if province == 'undefined':
province = None
if date1 and date2:
date1 = datetime.datetime.strptime(str(request.GET['date1']), '%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(request.GET['date2']), '%Y-%m-%d').date()
filters['date__gte'] = date1
filters['date__lte'] = date2
search = request.GET.get('search')
transports = self.queryset.filter(**filters).order_by("-date")
if search:
if search != 'undefined' and search.strip():
transports = transports.filter(
build_query(self.filterset_class.Meta.fields, search)
)
page_size = request.query_params.get('page_size', None)
if page_size:
self.pagination_class.page_size = int(page_size)
page = self.paginate_queryset(transports)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.serializer_class(transports, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
def create(self, request, *args, **kwargs):
file = request.FILES['file'].read()
wb_obj = openpyxl.load_workbook(filename=BytesIO(file))
sheet = wb_obj.active
headers = [str(cell).strip() for cell in next(sheet.iter_rows(values_only=True))]
field_map = {
"کد رهگیری خودرو": "tracking_code",
# "استان مقصد": "province",
# "شهرستان مقصد": "city",
# "محصول": "product",
"مقصد": "kill_house_name",
"ش جهادی مقصد": "part_id_code",
}
created_list = []
for row in sheet.iter_rows(min_row=2, values_only=True):
if row is None:
continue
row_data = dict(zip(headers, row))
driver_name = row_data.get("نام راننده")
record_data = {}
for col_name, model_field in field_map.items():
if col_name in row_data:
value = row_data[col_name]
record_data[model_field] = value
obj, created = Driver.objects.update_or_create(
driver_name=driver_name,
defaults=record_data,
)
created_list.append({
"driver_name": obj.driver_name,
})
return Response({'result':'ok'},status=status.HTTP_201_CREATED)
def update(self, request, *args, **kwargs):
tracking_code = request.data.get('tracking_code')
driver = Driver.objects.filter(
tracking_code=tracking_code,
).first()
if driver:
date_str = request.data.get('expire_licence_date')
expire_date = None
if date_str and isinstance(date_str, str):
try:
parts = [int(x) for x in date_str.split("/")]
if len(parts) == 3:
expire_date = convert_to_miladi(parts[0], parts[1], parts[2])
except (ValueError, IndexError) as e:
pass
update_fields = [
'car_id', 'driver_name', 'owner_name', 'pelak',
'weight', 'car_type', 'health_permit'
]
for field in update_fields:
if field in request.data:
setattr(driver, field, request.data[field])
if expire_date is not None:
driver.expire_licence_date = expire_date
driver.save()
return Response({'result':'ok'},status=status.HTTP_200_OK)
class TransportCarcassDashboardView(APIView):
permission_classes = [AllowAny]
def get(self,request):
search = request.GET.get('search')
type_role = request.GET.get('role')
province = request.GET.get('province')
if province == 'undefined':
province = None
date1 = request.GET.get('date1') or None
date2 = request.GET.get('date2') or None
if type_role:
if type_role == 'KillHouse':
filters_kill_house = {}
if province:
filters_kill_house['Province'] = province
kill_house_filterset_class = KillHouseFilterSet
kill_house = KillHouse.objects.filter(**filters_kill_house).order_by('id')
if search:
if search != 'undefined' and search.strip():
kill_house = kill_house.filter(
build_query(kill_house_filterset_class.Meta.fields, search)
)
kill_house = kill_house.values_list('PartIdCode',flat=True)
bars = TransportCarcassDetail.objects.filter(jihadi_origin__in=kill_house, trash=False)
buy_bars = TransportingDetail.objects.filter(DesPartIdCode__in=kill_house,
trash=False,Date__date__gte='2025-03-21',
TrackingStatusDescription__in=("تایید تخلیه",'بارگیری')).only(
'GoodAmount', 'Out')
all_products_transport_carcass = AllProductsTransport.objects.filter(
trash=False,
product='گوشت مرغ تازه',
jihadi_origin__in=kill_house
)
all_products_transport = AllProductsTransport.objects.filter(
trash=False,
product='مرغ زنده -جهت كشتار',
jihadi_destination__in=kill_house
)
if date1:
date1 = datetime.datetime.strptime(str(date1), '%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(date2), '%Y-%m-%d').date()
bars = bars.filter(Q(product_date__gte=date1, product_date__lte=date2, product_date__isnull=False) |
Q(date__gte=date1, date__lte=date2, product_date__isnull=True))
all_products_transport_carcass = all_products_transport_carcass.filter(
date__gte=date1, date__lte=date2, date__isnull=False
)
date_1_for_buy_bars = date1 - datetime.timedelta(days=1)
date_2_for_buy_bars = date2 - datetime.timedelta(days=1)
buy_bars = buy_bars.filter(Date__date__gte=date_1_for_buy_bars, Date__date__lte=date_2_for_buy_bars)
all_products_transport = all_products_transport.filter(
date__gte=date_1_for_buy_bars, date__lte=date_2_for_buy_bars, date__isnull=False
)
aggregation = bars.aggregate(
total=Sum('quantity'),
input_total=Sum('quantity', filter=Q(out=False)),
output_total=Sum('quantity', filter=Q(out=True)),
input_count=Count('id', filter=Q(out=False)),
output_count=Count('id', filter=Q(out=True)),
total_count=Count('id'),
)
all_products_transport_carcass_aggregation = all_products_transport_carcass.aggregate(
total=Sum('quantity'),
input_total=Sum('quantity', filter=Q(out=False)),
output_total=Sum('quantity', filter=Q(out=True)),
input_count=Count('id', filter=Q(out=False)),
output_count=Count('id', filter=Q(out=True)),
total_count=Count('id'),
)
buy_aggregation = buy_bars.aggregate(
total=Sum('GoodAmount'),
input_total=Sum('GoodAmount', filter=Q(Out=False)),
output_total=Sum('GoodAmount', filter=Q(Out=True)),
input_count=Count('id', filter=Q(Out=False)),
output_count=Count('id', filter=Q(Out=True)),
total_count=Count('id')
)
all_products_transport_aggregation = all_products_transport.aggregate(
total=Sum('quantity'),
input_total=Sum('quantity', filter=Q(out=False)),
output_total=Sum('quantity', filter=Q(out=True)),
input_count=Count('id', filter=Q(out=False)),
output_count=Count('id', filter=Q(out=True)),
total_count=Count('id'),
)
# ادغام aggregationها
aggregation['total'] = (aggregation.get('total') or 0) + (all_products_transport_carcass_aggregation.get('total') or 0)
aggregation['input_total'] = (aggregation.get('input_total') or 0) + (all_products_transport_carcass_aggregation.get('input_total') or 0)
aggregation['output_total'] = (aggregation.get('output_total') or 0) + (all_products_transport_carcass_aggregation.get('output_total') or 0)
aggregation['input_count'] = (aggregation.get('input_count') or 0) + (all_products_transport_carcass_aggregation.get('input_count') or 0)
aggregation['output_count'] = (aggregation.get('output_count') or 0) + (all_products_transport_carcass_aggregation.get('output_count') or 0)
aggregation['total_count'] = (aggregation.get('total_count') or 0) + (all_products_transport_carcass_aggregation.get('total_count') or 0)
buy_aggregation['total'] = (buy_aggregation.get('total') or 0) + (all_products_transport_aggregation.get('total') or 0)
buy_aggregation['input_total'] = (buy_aggregation.get('input_total') or 0) + (all_products_transport_aggregation.get('input_total') or 0)
buy_aggregation['output_total'] = (buy_aggregation.get('output_total') or 0) + (all_products_transport_aggregation.get('output_total') or 0)
buy_aggregation['input_count'] = (buy_aggregation.get('input_count') or 0) + (all_products_transport_aggregation.get('input_count') or 0)
buy_aggregation['output_count'] = (buy_aggregation.get('output_count') or 0) + (all_products_transport_aggregation.get('output_count') or 0)
buy_aggregation['total_count'] = (buy_aggregation.get('total_count') or 0) + (all_products_transport_aggregation.get('total_count') or 0)
total_count = aggregation['total_count'] or 0
total_bars_quantity = aggregation['total'] or 0
total_input_bars_quantity = aggregation['input_total'] or 0
total_output_bars_quantity = aggregation['output_total'] or 0
input_bars_count = aggregation['input_count'] or 0
output_bars_count = aggregation['output_count'] or 0
if total_count > 0:
total_input_bars_percent = round(
(total_input_bars_quantity / (total_input_bars_quantity + total_output_bars_quantity)) * 100, 1)
total_output_bars_percent = round(
(total_output_bars_quantity / (total_input_bars_quantity + total_output_bars_quantity)) * 100,
1)
else:
total_input_bars_percent = 0
total_output_bars_percent = 0
return Response({
"role": 'کشتارگاه',
"product": 'مرغ گرم',
"bars": int(total_count),
"total_bars_wight": int(total_bars_quantity),
"input_bars": int(input_bars_count),
"total_input_bars_wight": int(total_input_bars_quantity),
"total_input_buy_bars_wight": int(((buy_aggregation['input_total'] or 0) * 2.5) *0.75),
"total_input_bars_percent": total_input_bars_percent,
"output_bars": int(output_bars_count),
"total_output_bars_wight": int(total_output_bars_quantity),
"total_output_buy_bars_wight": int(((buy_aggregation['output_total'] or 0) * 2.5) *0.75),
"total_output_bars_percent": total_output_bars_percent,
"total_ware_house": int((((buy_aggregation['input_total'] or 0) * 2.5) *0.75) + (((buy_aggregation['output_total'] or 0) * 2.5) *0.75)),
"total_input_buy_bars_count": buy_aggregation['input_count'] or 0,
"total_output_buy_bars_count": buy_aggregation['output_count'] or 0,
"total_count_kill_house": len(kill_house),
"last_update": self._get_last_update_date_for_dashboard(bars, all_products_transport_carcass),
})
else:
filters_steward = {}
if province:
filters_steward['province'] = province
steward = Guilds.objects.filter(**filters_steward,trash=False, is_steward=True).order_by('id')
steward_filterset_class = GuildsFilterSet
if search:
if search != 'undefined' and search.strip():
steward = steward.filter(
build_query(steward_filterset_class.Meta.fields, search)
)
steward = steward.values_list('jihadi_code',flat=True)
date1 = request.GET.get('date1') or None
date2 = request.GET.get('date2') or None
bars = TransportCarcassDetail.objects.filter(
Q(jihadi_origin__in=steward) | Q(jihadi_destination__in=steward)
, trash=False).order_by('-modify_date')
all_products_transport_steward = AllProductsTransport.objects.filter(
trash=False,
product='گوشت مرغ تازه',
).filter(
Q(jihadi_origin__in=steward) | Q(jihadi_destination__in=steward)
)
if date1:
date1 = datetime.datetime.strptime(str(date1), '%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(date2), '%Y-%m-%d').date()
bars = bars.filter(product_date__gte=date1, product_date__lte=date2)
all_products_transport_steward = all_products_transport_steward.filter(
date__gte=date1, date__lte=date2, date__isnull=False
)
aggregation = bars.aggregate(
total=Sum('quantity', filter=Q(jihadi_origin__in=steward)),
input_total=Sum('quantity', filter=Q(out=False, jihadi_origin__in=steward)),
output_total=Sum('quantity', filter=Q(out=True, jihadi_origin__in=steward)),
input_count=Count('id', filter=Q(out=False, jihadi_origin__in=steward)),
output_count=Count('id', filter=Q(out=True, jihadi_origin__in=steward)),
total_count=Count('id', filter=Q(jihadi_origin__in=steward)),
total_input_buy_bars_wight=Sum('quantity', filter=Q(jihadi_destination__in=steward, out=False)),
total_input_buy_bars_count=Count('id', filter=Q(jihadi_destination__in=steward, out=False)),
total_output_buy_bars_wight=Sum('quantity', filter=Q(jihadi_destination__in=steward, out=True)),
total_output_buy_bars_count=Count('id', filter=Q(jihadi_destination__in=steward, out=True)),
total_ware_house=Sum('quantity', filter=Q(jihadi_origin__in=steward)),
)
all_products_transport_steward_aggregation = all_products_transport_steward.aggregate(
total=Sum('quantity', filter=Q(jihadi_origin__in=steward)),
input_total=Sum('quantity', filter=Q(out=False, jihadi_origin__in=steward)),
output_total=Sum('quantity', filter=Q(out=True, jihadi_origin__in=steward)),
input_count=Count('id', filter=Q(out=False, jihadi_origin__in=steward)),
output_count=Count('id', filter=Q(out=True, jihadi_origin__in=steward)),
total_count=Count('id', filter=Q(jihadi_origin__in=steward)),
total_input_buy_bars_wight=Sum('quantity', filter=Q(jihadi_destination__in=steward, out=False)),
total_input_buy_bars_count=Count('id', filter=Q(jihadi_destination__in=steward, out=False)),
total_output_buy_bars_wight=Sum('quantity', filter=Q(jihadi_destination__in=steward, out=True)),
total_output_buy_bars_count=Count('id', filter=Q(jihadi_destination__in=steward, out=True)),
total_ware_house=Sum('quantity', filter=Q(jihadi_origin__in=steward)),
)
# ادغام aggregationها
aggregation['total'] = (aggregation.get('total') or 0) + (all_products_transport_steward_aggregation.get('total') or 0)
aggregation['input_total'] = (aggregation.get('input_total') or 0) + (all_products_transport_steward_aggregation.get('input_total') or 0)
aggregation['output_total'] = (aggregation.get('output_total') or 0) + (all_products_transport_steward_aggregation.get('output_total') or 0)
aggregation['input_count'] = (aggregation.get('input_count') or 0) + (all_products_transport_steward_aggregation.get('input_count') or 0)
aggregation['output_count'] = (aggregation.get('output_count') or 0) + (all_products_transport_steward_aggregation.get('output_count') or 0)
aggregation['total_count'] = (aggregation.get('total_count') or 0) + (all_products_transport_steward_aggregation.get('total_count') or 0)
aggregation['total_input_buy_bars_wight'] = (aggregation.get('total_input_buy_bars_wight') or 0) + (all_products_transport_steward_aggregation.get('total_input_buy_bars_wight') or 0)
aggregation['total_input_buy_bars_count'] = (aggregation.get('total_input_buy_bars_count') or 0) + (all_products_transport_steward_aggregation.get('total_input_buy_bars_count') or 0)
aggregation['total_output_buy_bars_wight'] = (aggregation.get('total_output_buy_bars_wight') or 0) + (all_products_transport_steward_aggregation.get('total_output_buy_bars_wight') or 0)
aggregation['total_output_buy_bars_count'] = (aggregation.get('total_output_buy_bars_count') or 0) + (all_products_transport_steward_aggregation.get('total_output_buy_bars_count') or 0)
aggregation['total_ware_house'] = (aggregation.get('total_ware_house') or 0) + (all_products_transport_steward_aggregation.get('total_ware_house') or 0)
total_count = aggregation['total_count'] or 0
total_bars_quantity = aggregation['total'] or 0
total_input_bars_quantity = aggregation['input_total'] or 0
total_output_bars_quantity = aggregation['output_total'] or 0
input_bars_count = aggregation['input_count'] or 0
output_bars_count = aggregation['output_count'] or 0
total_input_buy_bars_wight = aggregation['total_input_buy_bars_wight'] or 0
total_output_buy_bars_wight = aggregation['total_output_buy_bars_wight'] or 0
total_ware_house = total_input_buy_bars_wight + total_output_buy_bars_wight
total_input_buy_bars_count = aggregation['total_input_buy_bars_count'] or 0
total_output_buy_bars_count = aggregation['total_output_buy_bars_count'] or 0
if total_count > 0:
total_input_bars_percent = round((total_input_bars_quantity / (total_input_bars_quantity +total_output_bars_quantity) ) * 100, 1)
total_output_bars_percent = round((total_output_bars_quantity / (total_input_bars_quantity +total_output_bars_quantity)) * 100, 1)
else:
total_input_bars_percent = 0
total_output_bars_percent = 0
return Response({
"role": 'مباشر',
"product": 'گوشت مرغ تازه',
"bars": int(total_count),
"total_bars_wight": int(total_bars_quantity),
"input_bars": int(input_bars_count),
"total_input_bars_wight": int(total_input_bars_quantity),
"total_input_buy_bars_wight": int(total_input_buy_bars_wight),
"total_input_bars_percent": total_input_bars_percent,
"output_bars": int(output_bars_count),
"total_output_bars_wight": int(total_output_bars_quantity),
"total_output_buy_bars_wight": int(total_output_buy_bars_wight),
"total_output_bars_percent": total_output_bars_percent,
"total_ware_house": int(total_ware_house),
"total_count_steward": len(steward),
"last_update": self._get_last_update_date_for_dashboard(bars, all_products_transport_steward),
"total_input_buy_bars_count": int(total_input_buy_bars_count),
"total_output_buy_bars_count": int(total_output_buy_bars_count),
})
return Response('ok', status=status.HTTP_200_OK)
def _get_last_update_date_for_dashboard(self, queryset1, queryset2):
"""تابع helper برای دریافت آخرین تاریخ به‌روزرسانی از دو queryset"""
dates = []
if queryset1.exists():
first_obj = queryset1.first()
if first_obj and hasattr(first_obj, 'modify_date') and first_obj.modify_date:
dates.append(first_obj.modify_date)
if queryset2.exists():
first_obj = queryset2.first()
if first_obj and hasattr(first_obj, 'modify_date') and first_obj.modify_date:
dates.append(first_obj.modify_date)
return max(dates) if dates else None
class GuildsTransportCarcassViewSet(viewsets.ModelViewSet):
queryset = Guilds.objects.filter(trash=False)
serializer_class = GuildsForTransportCarcassSerializer
permission_classes = [AllowAny]
pagination_class = CustomPagination
filterset_class = TransportCarcassDetailFilterSet
def list(self, request, *args, **kwargs):
search = request.GET.get('search')
province = request.GET.get('province')
if province == 'undefined':
province = None
if 'code' in request.GET:
code = request.GET.get('code')
date1 = request.GET.get('date1')
filters={}
query_carcass = TransportCarcassDetail.objects.filter(
jihadi_destination=code,
trash=False
)
query_all_products = AllProductsTransport.objects.filter(
trash=False,
product='گوشت مرغ تازه',
jihadi_destination=code
)
if date1:
date1 = datetime.datetime.strptime(str(request.GET['date1']), '%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(request.GET['date2']), '%Y-%m-%d').date()
query_carcass = query_carcass.filter(
Q(
product_date__gte=date1,
product_date__lte=date2,
product_date__isnull=False
) |
Q(
date__gte=date1,
date__lte=date2,
product_date__isnull=True
)
)
query_all_products = query_all_products.filter(
date__gte=date1,
date__lte=date2,
date__isnull=False
)
if search and search != 'undefined' and search.strip():
query_carcass = query_carcass.filter(
build_query(self.filterset_class.Meta.fields, search)
)
query_all_products = query_all_products.filter(
build_query(AllProductsTransportFilterSet.Meta.fields, search)
)
carcass_list = list(query_carcass)
all_products_list = list(query_all_products)
def get_sort_date(obj):
if hasattr(obj, 'product_date') and obj.product_date:
return obj.product_date
elif hasattr(obj, 'date') and obj.date:
return obj.date
elif hasattr(obj, 'unloading_date') and obj.unloading_date:
return obj.unloading_date
return datetime.date.min
combined_list = []
for obj in carcass_list:
combined_list.append((get_sort_date(obj), 'carcass', obj))
for obj in all_products_list:
combined_list.append((get_sort_date(obj), 'all_products', obj))
combined_list.sort(key=lambda x: x[0], reverse=True)
sorted_objects = [obj for _, _, obj in combined_list]
page_size = request.query_params.get('page_size', None)
if page_size:
self.pagination_class.page_size = int(page_size)
paginator = self.pagination_class()
page = paginator.paginate_queryset(sorted_objects, request)
if page is not None:
serialized_data = []
for obj in page:
if hasattr(obj, 'product_date'):
serializer = TransportCarcassDetailSerializer(obj, context={'request': request})
serialized_data.append(serializer.data)
else:
serializer = AllProductsTransportSerializer(obj, context={'request': request})
data = serializer.data
data['product_date'] = obj.date
data['product'] = obj.product
data['quantity'] = obj.quantity
data['jihadi_destination'] = obj.jihadi_destination
serialized_data.append(data)
return paginator.get_paginated_response(serialized_data)
serialized_data = []
for obj in sorted_objects:
if hasattr(obj, 'product_date'):
serializer = TransportCarcassDetailSerializer(obj, context={'request': request})
serialized_data.append(serializer.data)
else:
serializer = AllProductsTransportSerializer(obj, context={'request': request})
data = serializer.data
data['product_date'] = obj.date
data['product'] = obj.product
data['quantity'] = obj.quantity
data['jihadi_destination'] = obj.jihadi_destination
serialized_data.append(data)
return Response(serialized_data, status=status.HTTP_200_OK)
filters_steward = {}
if province:
filters_steward['province'] = province
steward = Guilds.objects.filter(**filters_steward, trash=False, is_steward=False).order_by('id')
steward_filterset_class = GuildsFilterSet
if search and search != 'undefined' and search.strip():
steward = steward.filter(build_query(steward_filterset_class.Meta.fields, search))
steward_jihadi_codes = list(steward.values_list('jihadi_code', flat=True))
steward_jihadi_codes = [code for code in steward_jihadi_codes if code]
date1 = request.GET.get('date1')
date2 = request.GET.get('date2')
bars = TransportCarcassDetail.objects.filter(
trash=False,
jihadi_destination__in=steward_jihadi_codes
).order_by('-product_date')
all_products_transport = AllProductsTransport.objects.filter(
trash=False,
product='گوشت مرغ تازه',
jihadi_destination__in=steward_jihadi_codes
)
if date1:
date1 = datetime.datetime.strptime(str(date1), '%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(date2), '%Y-%m-%d').date()
bars = bars.filter(product_date__gte=date1, product_date__lte=date2)
all_products_transport = all_products_transport.filter(
date__gte=date1, date__lte=date2, date__isnull=False
)
bars_summary = bars.values('jihadi_destination').annotate(
total_input_buy_bars_wight=Sum('quantity', filter=Q(out=False)),
total_output_buy_bars_wight=Sum('quantity', filter=Q(out=True)),
total_ware_house=Sum('quantity'),
total_count=Count('id'),
total_count_input_buy=Count('id', filter=Q(out=False)),
total_count_output_buy=Count('id', filter=Q(out=True)),
)
all_products_summary = all_products_transport.values('jihadi_destination').annotate(
total_input_buy_bars_wight=Sum('quantity', filter=Q(out=False)),
total_output_buy_bars_wight=Sum('quantity', filter=Q(out=True)),
total_ware_house=Sum('quantity'),
total_count=Count('id'),
total_count_input_buy=Count('id', filter=Q(out=False)),
total_count_output_buy=Count('id', filter=Q(out=True)),
)
bars_dict = {}
for row in bars_summary:
code = row['jihadi_destination']
if code:
if code not in bars_dict:
bars_dict[code] = {
'total_input_buy_bars_wight': 0,
'total_output_buy_bars_wight': 0,
'total_ware_house': 0,
'total_count': 0,
'total_count_input_buy': 0,
'total_count_output_buy': 0,
}
bars_dict[code]['total_input_buy_bars_wight'] += row['total_input_buy_bars_wight'] or 0
bars_dict[code]['total_output_buy_bars_wight'] += row['total_output_buy_bars_wight'] or 0
bars_dict[code]['total_ware_house'] += row['total_ware_house'] or 0
bars_dict[code]['total_count'] += row['total_count'] or 0
bars_dict[code]['total_count_input_buy'] += row['total_count_input_buy'] or 0
bars_dict[code]['total_count_output_buy'] += row['total_count_output_buy'] or 0
for row in all_products_summary:
code = row['jihadi_destination']
if code:
if code not in bars_dict:
bars_dict[code] = {
'total_input_buy_bars_wight': 0,
'total_output_buy_bars_wight': 0,
'total_ware_house': 0,
'total_count': 0,
'total_count_input_buy': 0,
'total_count_output_buy': 0,
}
bars_dict[code]['total_input_buy_bars_wight'] += row['total_input_buy_bars_wight'] or 0
bars_dict[code]['total_output_buy_bars_wight'] += row['total_output_buy_bars_wight'] or 0
bars_dict[code]['total_ware_house'] += row['total_ware_house'] or 0
bars_dict[code]['total_count'] += row['total_count'] or 0
bars_dict[code]['total_count_input_buy'] += row['total_count_input_buy'] or 0
bars_dict[code]['total_count_output_buy'] += row['total_count_output_buy'] or 0
seen_jihadi_codes = set()
unique_stewards = []
for st in steward:
if st.jihadi_code and st.jihadi_code not in seen_jihadi_codes:
seen_jihadi_codes.add(st.jihadi_code)
unique_stewards.append(st)
unique_stewards.sort(
key=lambda st: (bars_dict.get(st.jihadi_code, {}) or {}).get('total_ware_house', 0) or 0,
reverse=True
)
steward = unique_stewards
page_size = request.query_params.get('page_size', None)
if page_size:
self.pagination_class.page_size = int(page_size)
page = self.paginate_queryset(steward)
if page is not None:
serializer = self.serializer_class(page, many=True, context={'request': request, 'bars_dict': bars_dict})
return self.get_paginated_response(serializer.data)
serializer = self.serializer_class(steward, many=True, context={'request': request, 'bars_dict': bars_dict})
return Response(serializer.data, status=status.HTTP_200_OK)
class GuildsTransportCarcassDashboardView(APIView):
permission_classes = [AllowAny]
def get(self,request):
search = request.GET.get('search')
province = request.GET.get('province')
if province == 'undefined':
province = None
filters_steward = {}
if province:
filters_steward['province'] = province
steward = Guilds.objects.filter(**filters_steward,trash=False, is_steward=False).order_by('id')
steward_filterset_class = GuildsFilterSet
if search:
if search != 'undefined' and search.strip():
steward = steward.filter(
build_query(steward_filterset_class.Meta.fields, search)
)
steward = steward.values_list('jihadi_code', flat=True)
date1 = request.GET.get('date1') or None
date2 = request.GET.get('date2') or None
bars = TransportCarcassDetail.objects.filter(
jihadi_destination__in=steward,
trash=False
)
all_products_transport = AllProductsTransport.objects.filter(
trash=False,
product='گوشت مرغ تازه',
jihadi_destination__in=steward
)
if date1:
date1 = datetime.datetime.strptime(str(date1), '%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(date2), '%Y-%m-%d').date()
bars = bars.filter(product_date__gte=date1, product_date__lte=date2)
all_products_transport = all_products_transport.filter(
date__gte=date1, date__lte=date2, date__isnull=False
)
aggregation = bars.aggregate(
total_input_buy_bars_wight=Sum('quantity', filter=Q(out=False)),
total_output_buy_bars_wight=Sum('quantity', filter=Q(out=True)),
total_ware_house=Sum('quantity'),
total_count=Count('id'),
total_count_input_buy=Count('id', filter=Q(out=False)),
total_count_output_buy=Count('id', filter=Q(out=True)),
last_update_carcass=Max('modify_date'),
)
all_products_aggregation = all_products_transport.aggregate(
total_input_buy_bars_wight=Sum('quantity', filter=Q(out=False)),
total_output_buy_bars_wight=Sum('quantity', filter=Q(out=True)),
total_ware_house=Sum('quantity'),
total_count=Count('id'),
total_count_input_buy=Count('id', filter=Q(out=False)),
total_count_output_buy=Count('id', filter=Q(out=True)),
last_update_all_products=Max('modify_date'),
)
total_input_buy_bars_wight = (aggregation['total_input_buy_bars_wight'] or 0) + (all_products_aggregation['total_input_buy_bars_wight'] or 0)
total_output_buy_bars_wight = (aggregation['total_output_buy_bars_wight'] or 0) + (all_products_aggregation['total_output_buy_bars_wight'] or 0)
total_ware_house = (aggregation['total_ware_house'] or 0) + (all_products_aggregation['total_ware_house'] or 0)
total_count = (aggregation['total_count'] or 0) + (all_products_aggregation['total_count'] or 0)
total_count_input_buy = (aggregation['total_count_input_buy'] or 0) + (all_products_aggregation['total_count_input_buy'] or 0)
total_count_output_buy = (aggregation['total_count_output_buy'] or 0) + (all_products_aggregation['total_count_output_buy'] or 0)
last_update_carcass = aggregation.get('last_update_carcass')
last_update_all_products = all_products_aggregation.get('last_update_all_products')
last_update = None
if last_update_carcass and last_update_all_products:
last_update = max(last_update_carcass, last_update_all_products)
elif last_update_carcass:
last_update = last_update_carcass
elif last_update_all_products:
last_update = last_update_all_products
if total_count > 0:
total_input_bars_percent = round((total_input_buy_bars_wight / total_ware_house) * 100, 1)
total_output_bars_percent = round((total_output_buy_bars_wight / total_ware_house) * 100, 1)
else:
total_input_bars_percent = 0
total_output_bars_percent = 0
return Response({
"role": 'صنف',
"product": 'گوشت مرغ تازه',
"total_input_buy_bars_wight": int(total_input_buy_bars_wight),
"total_output_buy_bars_wight": int(total_output_buy_bars_wight),
"total_ware_house": int(total_ware_house),
"total_input_buy_bars_percent": total_input_bars_percent,
"total_output_buy_bars_percent": total_output_bars_percent,
"total_count_guild": len(steward),
"last_update": last_update,
"total_input_buy_bars_count": int(total_count_input_buy),
"total_output_buy_bars_count": int(total_count_output_buy),
})
class ApiSendDifferentBarFromHatching(viewsets.ModelViewSet):
queryset = TransportingDetail.objects.filter(trash=False)
serializer_class = TransportingForClearanceCodeSerializer
permission_classes = [AllowAny]
pagination_class = CustomPagination
filterset_class = TransportingDetailFilterSet
def list(self, request, *args, **kwargs):
filters = {'trash': False}
filters_bar = {'trash': False}
if request.GET.get('date1') != 'None':
date1 = datetime.datetime.strptime(str(request.GET['date1']),
'%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(request.GET['date2']),
'%Y-%m-%d').date()
filters_bar['Date__date__gte'] = date1
filters_bar['Date__date__lte'] = date2
poultry = Hatching.objects.filter(**filters, PartIdCode=request.GET['licence_number'])
if poultry.exists():
bar = TransportingDetail.objects.filter(**filters_bar, hatching__in=poultry, TrackingStatusDescription__in=(
'تایید تخلیه', 'بارگیری'
)).exclude(
TrackingCode__in=request.data
).order_by('-Date')
quarantine_code = bar.values_list('TrackingCode', flat=True).distinct()
bar = bar.filter(TrackingCode__in=quarantine_code).order_by('-Date')
search = request.GET.get('search')
value = request.GET.get('value')
if search:
if search != 'undefined' and value.strip():
bar = bar.filter(
build_query(self.filterset_class.Meta.fields, value)
)
page_size = request.query_params.get('page_size', None)
if page_size:
self.pagination_class.page_size = int(page_size)
page = self.paginate_queryset(bar)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
ser_data = TransportingForClearanceCodeSerializer(bar, many=True).data
return Response(ser_data)
return Response([])
def fix_province():
province_list = [p['name'] for p in iranprovince]
wrong_records = TransportCarcassDetail.objects.filter(
~Q(origin_province__in=province_list) | ~Q(destination_province__in=province_list),
trash=False
)
for record in wrong_records:
record.save()
def fix_city():
province_list = [p['name'] for p in irancity]
wrong_records = TransportCarcassDetail.objects.filter(
~Q(origin_city__in=province_list) | ~Q(destination_city__in=province_list),
trash=False
)
for record in wrong_records:
record.save()
def update_product_date(request):
date1 = datetime.datetime.strptime(str(request.GET['date1']),
'%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(request.GET['date2']),
'%Y-%m-%d').date()
bars = TransportCarcassDetail.objects.filter(trash=False, product_date__isnull=True, date__gte=date1,date__lte=date2,
has_product_date=False)[:1000]
for bar in bars:
quarantine = bar.tracking
session = requests.Session()
session.mount('https://', SSLAdapter())
data = {'gid': str(quarantine)}
m = session.post('https://e.ivo.ir/Rahgiri/Gidprnt.aspx', data=data, verify=False,
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36'})
context = BeautifulSoup(m.text, 'html.parser')
try:
table = context.find_all('table')
if table[5:6]:
for i in table[5:6]:
row = i.find_all('tr')
for r in row[1:2]:
td = r.find('td')
shamsi_date =td.text.strip().split(':')[1]
year, month, day = map(int, shamsi_date.split('/'))
gregorian_date = jdatetime.date(year, month, day).togregorian()
bar.product_date = gregorian_date
bar.has_product_date = True
bar.save()
except:
bar.product_date=bar.date
bar.has_product_date = True
bar.save()
return HttpResponse(len(bars))
def update_product_date_cron():
bars = TransportCarcassDetail.objects.filter(trash=False, product_date__isnull=True,
has_product_date=False
).order_by('-date')[:600]
for bar in bars:
quarantine = bar.tracking
session = requests.Session()
session.mount('https://', SSLAdapter())
data = {'gid': str(quarantine)}
m = session.post('https://e.ivo.ir/Rahgiri/Gidprnt.aspx', data=data, verify=False,
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36'})
context = BeautifulSoup(m.text, 'html.parser')
bar.has_product_date=True
try:
table = context.find_all('table')
if table[5:6]:
for i in table[5:6]:
row = i.find_all('tr')
for r in row[1:2]:
td = r.find('td')
shamsi_date = td.text.strip().split(':')[1]
year, month, day = map(int, shamsi_date.split('/'))
gregorian_date = jdatetime.date(year, month, day).togregorian()
bar.product_date = gregorian_date
bar.has_product_date = True
bar.save()
except:
bar.product_date = bar.date
bar.has_product_date = True
bar.save()
@api_view(['GET'])
@permission_classes([AllowAny])
@csrf_exempt
def send_transport_carcass_detail_for_rasadyaar(request):
code = request.GET['code']
code = code.split(',')
kill_house = KillHouse.objects.filter(trash=False,PartIdCode__in=code).order_by('id')
date1 = request.GET.get('date1')
date2 = request.GET.get('date2')
date1 = datetime.datetime.strptime(str(date1), '%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(date2), '%Y-%m-%d').date()
bars = TransportCarcassDetail.objects.filter(
Q(product_date__gte=date1, product_date__lte=date2, product_date__isnull=False) |
Q(date__gte=date1, date__lte=date2, product_date__isnull=True),
trash=False
).only('quantity','out','id','jihadi_origin','tracking')
date_1_for_buy_bars = date1 - datetime.timedelta(days=1)
date_2_for_buy_bars = date2 - datetime.timedelta(days=1)
buy_bars = TransportingDetail.objects.filter(
Date__date__gte=date_1_for_buy_bars,
Date__date__lte=date_2_for_buy_bars,
trash=False,
TrackingStatusDescription__in=("تایید تخلیه",'بارگیری')
).only('GoodAmount','Out','id','DesPartIdCode','TrackingCode')
quarantine_bars = list(bars.values_list('tracking',flat=True).distinct())
quarantine_buy = list(buy_bars.values_list('TrackingCode',flat=True).distinct())
all_track = quarantine_bars + quarantine_buy
all_products_carcass = AllProductsTransport.objects.filter(
date__gte=date1,
date__lte=date2,
trash=False,
product='گوشت مرغ تازه'
).exclude(tracking__in=all_track).only('quantity','out','id','jihadi_origin', 'tracking')
all_products_live = AllProductsTransport.objects.filter(
date__gte=date_1_for_buy_bars, date__lte=date_2_for_buy_bars, date__isnull=False,
trash=False,
product='مرغ زنده -جهت كشتار'
).exclude(tracking__in=all_track).only('quantity','out','id','jihadi_destination', 'tracking')
bars_summary = bars.values('jihadi_origin').annotate(
total=Sum('quantity'),
input_total=Sum('quantity', filter=Q(out=False)),
output_total=Sum('quantity', filter=Q(out=True)),
input_count=Count('id', filter=Q(out=False)),
output_count=Count('id', filter=Q(out=True)),
total_count=Count('id'),
)
all_products_carcass_summary = all_products_carcass.values('jihadi_origin').annotate(
total=Sum('quantity'),
input_total=Sum('quantity', filter=Q(out=False)),
output_total=Sum('quantity', filter=Q(out=True)),
input_count=Count('id', filter=Q(out=False)),
output_count=Count('id', filter=Q(out=True)),
total_count=Count('id'),
)
buy_summary = buy_bars.values('DesPartIdCode').annotate(
total=Sum('GoodAmount'),
input_total=Sum('GoodAmount', filter=Q(Out=False)),
output_total=Sum('GoodAmount', filter=Q(Out=True)),
input_count=Count('id', filter=Q(Out=False)),
output_count=Count('id', filter=Q(Out=True)),
total_count=Count('id'),
)
all_products_live_summary = all_products_live.values('jihadi_destination').annotate(
total=Sum('quantity'),
input_total=Sum('quantity', filter=Q(out=False)),
output_total=Sum('quantity', filter=Q(out=True)),
input_count=Count('id', filter=Q(out=False)),
output_count=Count('id', filter=Q(out=True)),
total_count=Count('id'),
)
bars_dict = {}
for row in bars_summary:
key = row['jihadi_origin']
if key:
if key not in bars_dict:
bars_dict[key] = {
'total': 0,
'input_total': 0,
'output_total': 0,
'input_count': 0,
'output_count': 0,
'total_count': 0,
}
bars_dict[key]['total'] += row['total'] or 0
bars_dict[key]['input_total'] += row['input_total'] or 0
bars_dict[key]['output_total'] += row['output_total'] or 0
bars_dict[key]['input_count'] += row['input_count'] or 0
bars_dict[key]['output_count'] += row['output_count'] or 0
bars_dict[key]['total_count'] += row['total_count'] or 0
for row in all_products_carcass_summary:
key = row['jihadi_origin']
if key:
if key not in bars_dict:
bars_dict[key] = {
'total': 0,
'input_total': 0,
'output_total': 0,
'input_count': 0,
'output_count': 0,
'total_count': 0,
}
bars_dict[key]['total'] += row['total'] or 0
bars_dict[key]['input_total'] += row['input_total'] or 0
bars_dict[key]['output_total'] += row['output_total'] or 0
bars_dict[key]['input_count'] += row['input_count'] or 0
bars_dict[key]['output_count'] += row['output_count'] or 0
bars_dict[key]['total_count'] += row['total_count'] or 0
buy_dict = {}
for row in buy_summary:
key = row['DesPartIdCode']
if key not in buy_dict:
buy_dict[key] = {
'total': 0,
'input_total': 0,
'output_total': 0,
'input_count': 0,
'output_count': 0,
'total_count': 0,
}
buy_dict[key]['total'] += row['total'] or 0
buy_dict[key]['input_total'] += row['input_total'] or 0
buy_dict[key]['output_total'] += row['output_total'] or 0
buy_dict[key]['input_count'] += row['input_count'] or 0
buy_dict[key]['output_count'] += row['output_count'] or 0
buy_dict[key]['total_count'] += row['total_count'] or 0
for row in all_products_live_summary:
key = row['jihadi_destination']
if key:
if key not in buy_dict:
buy_dict[key] = {
'total': 0,
'input_total': 0,
'output_total': 0,
'input_count': 0,
'output_count': 0,
'total_count': 0,
}
buy_dict[key]['total'] += row['total'] or 0
buy_dict[key]['input_total'] += row['input_total'] or 0
buy_dict[key]['output_total'] += row['output_total'] or 0
buy_dict[key]['input_count'] += row['input_count'] or 0
buy_dict[key]['output_count'] += row['output_count'] or 0
buy_dict[key]['total_count'] += row['total_count'] or 0
kill_house = list(kill_house)
kill_house.sort(
key=lambda kh: (bars_dict.get(kh.PartIdCode, {}) or {}).get('total', 0) or 0,
reverse=True
)
serializer = KillHouseForTransportCarcassForRassadyaarSerializer(
kill_house, many=True, context={'request': request, 'bars_dict': bars_dict, 'buy_dict': buy_dict}
)
return Response(serializer.data, status=status.HTTP_200_OK)
@api_view(["POST"])
@permission_classes([AllowAny])
@csrf_exempt
def delete_free_bar_from_rasadyaar(request):
code = request.data
code = dict(code)['code']
bars = TransportingDetail.objects.filter(trash=False, Out=True, TrackingCode__in=code,
).exclude(TrackingStatusDescription__in=(
'تایید تخلیه', 'بارگیری'))
ser_data = TransportingDetailForUpdateSerializer(bars, many=True).data
return Response(ser_data, status=status.HTTP_200_OK)
@api_view(["POST"])
@permission_classes([AllowAny])
@csrf_exempt
def fix_number(request):
data = request.data
poultreis = Poultry.objects.filter(trash=False, PartIdCode__in=list(data.keys()))
result_list=[]
for k, v in data.items():
poultry = poultreis.filter(PartIdCode=k).first()
if poultry and poultry.Mobile != v:
result_list.append({k:poultry.Mobile})
return Response(result_list)
@api_view(["POST"])
@permission_classes([AllowAny])
@csrf_exempt
def get_evacuation_detail_by_request_code(request):
request_code = request.data.get('RequestCode')
if not request_code:
return Response({'detail': 'RequestCode is required'}, status=status.HTTP_400_BAD_REQUEST)
hatching = Hatching.objects.filter(RequestCode=request_code, trash=False).first()
if not hatching:
return Response([], status=status.HTTP_200_OK)
evacuations = EvacuationDetail.objects.filter(hatching=hatching, trash=False).order_by('-create_date')
serializer = EvacuationDetailSerializer(evacuations, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
@api_view(['POST'])
@permission_classes([AllowAny])
def get_evacuation_details_by_request_codes(request):
request_codes = request.data.get('codes', [])
if not request_codes or not isinstance(request_codes, list):
return Response({'detail': 'RequestCodes list is required'}, status=status.HTTP_400_BAD_REQUEST)
result = {}
hatchings = Hatching.objects.filter(RequestCode__in=request_codes, trash=False)
for hatching in hatchings:
evacuations = EvacuationDetail.objects.filter(hatching=hatching, trash=False).order_by('-create_date')
serializer = EvacuationDetailSerializer(evacuations, many=True)
result[hatching.RequestCode] = serializer.data
for code in request_codes:
if code not in result:
result[code] = []
return Response(result, status=status.HTTP_200_OK)
class InquiryCredentialsViewSet(viewsets.ModelViewSet):
queryset = InquiryCredentials.objects.all()
serializer_class = InquiryCredentialsSerializer
permission_classes = [AllowAny]
def list(self, request, *args, **kwargs):
inquiry_credentials = InquiryCredentials.objects.filter(trash=False).first()
# inquiry_credentials, created = InquiryCredentials.objects.get_or_create(trash=False)
serializer = self.serializer_class(inquiry_credentials)
return Response(serializer.data, status=status.HTTP_200_OK)
def update(self, request, *args, **kwargs):
inquiry_credentials = InquiryCredentials.objects.filter(trash=False).first()
serializer = self.serializer_class(inquiry_credentials, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
class EvacuationDetailViewSet(viewsets.ModelViewSet):
queryset = EvacuationDetail.objects.filter(trash=False)
serializer_class = EvacuationDetailSerializer
permission_classes = [AllowAny]
pagination_class = CustomPagination
def create(self, request, *args, **kwargs):
data_list = request.data if isinstance(request.data, list) else [request.data]
total_created = 0
total_updated = 0
for item_data in data_list:
evacuation_details = item_data.get('EvacuationDetail', [])
if not evacuation_details or len(evacuation_details) == 0:
continue
request_code = item_data.get('RequestCode')
if not request_code:
continue
hatching = Hatching.objects.filter(RequestCode=request_code, trash=False).first()
if not hatching:
continue
for evacuation_data in evacuation_details:
clean_data = evacuation_data.copy()
external_id = clean_data.pop('Id', None)
if external_id is not None:
clean_data['ExternalId'] = external_id
evacuation = None
if external_id:
evacuation = EvacuationDetail.objects.filter(
ExternalId=external_id,
trash=False
).first()
if evacuation:
for key, value in clean_data.items():
setattr(evacuation, key, value)
evacuation.hatching = hatching
evacuation.save()
total_updated += 1
else:
clean_data['hatching'] = hatching
EvacuationDetail.objects.create(**clean_data)
total_created += 1
return Response({
"result": "با موفقیت ثبت شد",
"created": total_created,
"updated": total_updated
}, status=status.HTTP_201_CREATED)
def list(self, request, *args, **kwargs):
evacuations = self.filter_queryset(self.get_queryset())
search = request.GET.get('search')
if search:
if search != 'undefined' and search.strip():
evacuations = evacuations.filter(
build_query(['TrackingCode', 'SourceUnitName', 'DesUnitName'], search)
)
page_size = request.query_params.get('page_size', None)
if page_size:
self.pagination_class.page_size = int(page_size)
page = self.paginate_queryset(evacuations.order_by('-issue_date', '-create_date'))
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.serializer_class(evacuations.order_by('-issue_date', '-create_date'), many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
@api_view(['GET'])
@permission_classes([AllowAny])
@csrf_exempt
def evacuation_report_type_summary(request):
queryset = EvacuationDetail.objects.filter(trash=False).exclude(
ReportTypeString__isnull=True
).exclude(
ReportTypeString=''
)
report_type_counter = queryset.values('ReportTypeString').annotate(
count=Count('id')
)
type_relations = defaultdict(set)
for item in queryset.values('ReportTypeString', 'ReportType').distinct():
report_type_string = item['ReportTypeString']
report_type_value = item['ReportType']
if report_type_value is not None:
type_relations[report_type_string].add(report_type_value)
report_types = []
for entry in report_type_counter.order_by('-count', 'ReportTypeString'):
report_type_string = entry['ReportTypeString']
associated_types = sorted(type_relations.get(report_type_string, []))
report_types.append({
"report_type_string": report_type_string,
"count": entry['count'],
"report_types": associated_types,
})
distinct_count = len(report_types)
mapping_is_unique = all(len(values) <= 1 for values in type_relations.values())
return Response({
"total_report_types": distinct_count,
"report_types": report_types,
"report_type_matches_report_type_string": mapping_is_unique,
}, status=status.HTTP_200_OK)
class AllProductsTransportViewSet(viewsets.ModelViewSet):
queryset = AllProductsTransport.objects.filter(trash=False)
serializer_class = AllProductsTransportCustomSerializer
permission_classes = [AllowAny]
pagination_class = CustomPagination
filterset_class = AllProductsTransportFilterSet
def list(self, request, *args, **kwargs):
filters = {"trash": False}
product_type = request.GET.get('product_type')
destination_province = request.GET.get('destination_province')
date1 = request.GET.get('date1')
date2 = request.GET.get('date2')
search = request.GET.get('search')
if product_type and product_type != 'undefined':
filters['product'] = product_type
if destination_province and destination_province != 'undefined':
if destination_province == 'مرکزی':
filters['destination_province'] = 'مرکزي'
else:
filters['destination_province'] = destination_province
if date1 and date2 and date1 != 'undefined' and date2 != 'undefined':
try:
start_date = datetime.datetime.strptime(str(date1), '%Y-%m-%d')
end_date = datetime.datetime.strptime(str(date2), '%Y-%m-%d')
filters['date__gte'] = start_date
filters['date__lte'] = end_date
except ValueError:
pass
# بهینه‌سازی: استفاده از select_related برای جلوگیری از N+1 queries
# و اعمال order_by فقط یک بار
transports = AllProductsTransport.objects.select_related('hatching').filter(**filters)
if search and search != 'undefined' and search.strip():
transports = transports.filter(
build_query(self.filterset_class.Meta.fields, search)
)
# اعمال order_by فقط یک بار در آخر
transports = transports.order_by('-date', '-create_date')
page_size = request.query_params.get('page_size', None)
if page_size:
self.pagination_class.page_size = int(page_size)
page = self.paginate_queryset(transports)
# بهینه‌سازی: ایجاد cache برای Province و City در context برای جلوگیری از N+1 queries
location_cache = {}
context = self.get_serializer_context()
context['location_cache'] = location_cache
if page is not None:
serializer = self.get_serializer(page, many=True, context=context)
return self.get_paginated_response(serializer.data)
serializer = self.serializer_class(transports, many=True, context=context)
return Response(serializer.data, status=status.HTTP_200_OK)
def create(self, request, *args, **kwargs):
if 'file' in request.FILES:
return self._import_from_excel(request)
data = request.data
if isinstance(data, list):
# Bulk create
created_objects = []
for item in data:
tracking = item.get('tracking')
if tracking:
obj, created = AllProductsTransport.objects.update_or_create(
tracking=tracking,
defaults=item
)
created_objects.append(obj)
serializer = self.get_serializer(created_objects, many=True)
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
# Single create
return super().create(request, *args, **kwargs)
def _import_from_excel(self, request):
"""Import data from Excel file"""
file = request.FILES['file'].read()
wb_obj = openpyxl.load_workbook(filename=BytesIO(file))
sheet = wb_obj.active
headers = [str(cell).strip() if cell else '' for cell in next(sheet.iter_rows(values_only=True))]
field_map = {
"id": "record_id",
"مقصد قبلی": "destination_prev",
"تغییر مقصد": "destination_changed",
"کد رهگیری": "tracking",
"رهگیری": "tracking",
"تاریخ": "date",
"محصول": "product",
"اقلام": "items",
"مقدار": "quantity",
"واحد": "unit",
"استان مبدا": "origin_province",
"شهرستان مبدا": "origin_city",
"مبدا": "origin",
"استان مقصد": "destination_province",
"شهرستان مقصد": "destination_city",
"مقصد": "destination",
"ش جهادی مبدا": "jihadi_origin",
"ش جهادی مقصد": "jihadi_destination",
"مالک": "owner",
"کد رهگیری خودرو": "car_tracking_code",
"نام راننده": "driver_name",
"وزن پر": "gross_weight",
"وزن خالی": "tare_weight",
"وزن": "net_weight",
"کد باسکول": "scale_code",
"نام باسکول": "scale_name",
"قبض باسکول": "scale_receipt",
"تاریخ تخلیه": "unloading_date",
"تخلیه": "unloading",
}
created_count = 0
updated_count = 0
skipped_count = 0
for row in sheet.iter_rows(min_row=2, values_only=True):
if not row or all(cell is None for cell in row):
continue
row_data = dict(zip(headers, row))
tracking_val = row_data.get("کد رهگیری") or row_data.get("رهگیری")
province_name = row_data.get("شهرستان مقصد") or row_data.get("شهرستان مقصد")
jihadi_origin_code = row_data.get("ش جهادی مبدا") or row_data.get("ش جهادی مبدا")
print(province_name)
if not tracking_val:
continue
existing_record = AllProductsTransport.objects.filter(tracking=tracking_val, trash=False).first()
unloading_val = row_data.get("تخلیه", "").strip() if row_data.get("تخلیه") else ""
if unloading_val in ["تخلیه.", "تخلیه"] and existing_record:
skipped_count += 1
continue
record_data = {}
for col_name, model_field in field_map.items():
if col_name in row_data:
value = row_data[col_name]
if model_field in ["date", "unloading_date"] and value:
try:
if isinstance(value, str):
if '/' in value:
parts = value.split('/')
if len(parts) == 3:
y, m, d = map(int, parts)
value = convert_to_miladi(y, m, d)
else:
value = datetime.datetime.strptime(value, '%Y-%m-%d').date()
elif hasattr(value, "year"):
value = convert_to_miladi(value.year, value.month, value.day)
except (ValueError, AttributeError, IndexError):
value = None
if model_field == "quantity" and value:
try:
if isinstance(value, str):
value = float(value.replace(',', ''))
else:
value = float(value)
except (ValueError, TypeError):
value = None
if model_field in ["gross_weight", "tare_weight", "net_weight"] and value:
try:
if isinstance(value, str):
value = float(value.replace(',', ''))
else:
value = float(value)
except (ValueError, TypeError):
value = None
record_data[model_field] = value
hatching_obj = None
try:
permit_map = get_hatching_permit_code(tracking_val)
permit_code = permit_map.get(str(tracking_val))
if permit_code:
hatching_obj = Hatching.objects.filter(PartIdCode=jihadi_origin_code, trash=False).last()
except Exception:
pass
if existing_record:
for key, value in record_data.items():
setattr(existing_record, key, value)
if hatching_obj:
existing_record.hatching = hatching_obj
existing_record.save()
if existing_record.destination_province and existing_record.origin_province:
if existing_record.destination_province != existing_record.origin_province:
existing_record.out = True
existing_record.save()
updated_count += 1
else:
record_data["tracking"] = tracking_val
new_record = AllProductsTransport(**record_data)
if hatching_obj:
new_record.hatching = hatching_obj
new_record.save()
if new_record.destination_province and new_record.origin_province:
if new_record.destination_province != new_record.origin_province:
new_record.out = True
new_record.save()
created_count += 1
return Response({
'result': 'ok',
'created': created_count,
'updated': updated_count,
'skipped': skipped_count,
'message': f'{created_count} رکورد جدید اضافه شد، {updated_count} رکورد به‌روزرسانی شد، {skipped_count} رکورد رد شد (تخلیه شده)'
}, status=status.HTTP_201_CREATED)
class AllProductsTransportDashboardView(APIView):
permission_classes = [AllowAny]
def get(self, request):
role = request.GET.get('role')
province = request.GET.get('province')
search = request.GET.get('search')
product_type = request.GET.get('product_type')
date1 = request.GET.get('date1') or None
date2 = request.GET.get('date2') or None
filters={'trash':False}
if province == 'undefined':
province = None
if product_type and product_type != 'undefined':
filters['product'] = product_type
if date1 and date2 and date1 != 'undefined' and date2 != 'undefined':
try:
start_date = datetime.datetime.strptime(str(date1), '%Y-%m-%d')
end_date = datetime.datetime.strptime(str(date2), '%Y-%m-%d')
filters['date__gte'] = start_date
filters['date__lte'] = end_date
except ValueError:
pass
destination_province = request.GET.get('destination_province')
kill_house_filterset_class = AllProductsTransportFilterSet
if destination_province and destination_province != 'undefined':
if destination_province == 'مرکزی':
filters['destination_province'] = 'مركزي'
else:
filters['destination_province'] = destination_province
queryset = AllProductsTransport.objects.filter(**filters)
if search and search != 'undefined' and search.strip():
queryset = queryset.filter(
build_query(kill_house_filterset_class.Meta.fields, search)
)
if role:
if role == 'KillHouse':
filters_query = {'trash':False}
filters_kill_house = {}
if province:
filters_kill_house['Province'] = province
kill_house_filterset_class = AllProductsTransportFilterSet
kill_house = KillHouse.objects.filter(**filters_kill_house).order_by('id')
if search and search != 'undefined' and search.strip():
kill_house = kill_house.filter(
build_query(kill_house_filterset_class.Meta.fields, search)
)
kill_house_codes = kill_house.values_list('PartIdCode', flat=True)
filters_query['jihadi_origin__in']=kill_house_codes
# bars = queryset.filter(jihadi_origin__in=kill_house_codes)
if destination_province and destination_province != 'undefined':
filters_query['destination_province'] = normalize_persian_arabic_text(destination_province)
bars = queryset.filter(**filters_query)
aggregation = bars.aggregate(
total=Sum('quantity'),
input_total=Sum('quantity', filter=Q(out=False)),
output_total=Sum('quantity', filter=Q(out=True)),
input_count=Count('id', filter=Q(out=False)),
output_count=Count('id', filter=Q(out=True)),
total_count=Count('id'),
)
total_count = aggregation['total_count'] or 0
total_quantity = aggregation['total'] or 0
input_quantity = aggregation['input_total'] or 0
output_quantity = aggregation['output_total'] or 0
input_count = aggregation['input_count'] or 0
output_count = aggregation['output_count'] or 0
if total_count > 0 and (input_quantity + output_quantity) > 0:
input_percent = round((input_quantity / (input_quantity + output_quantity)) * 100, 1)
output_percent = round((output_quantity / (input_quantity + output_quantity)) * 100, 1)
else:
input_percent = 0
output_percent = 0
last_update = bars.order_by('-modify_date').values_list('modify_date', flat=True).first()
return Response({
"role": 'کشتارگاه',
"product": product_type,
"bars": int(total_count),
"total_bars_wight": int(total_quantity),
"input_bars": int(input_count),
"total_input_bars_wight": int(input_quantity),
"total_input_bars_percent": input_percent,
"output_bars": int(output_count),
"total_output_bars_wight": int(output_quantity),
"total_output_bars_percent": output_percent,
"total_count_kill_house": kill_house.count(),
"last_update": last_update,
}, status=status.HTTP_200_OK)
else:
filters_steward = {}
filters_query = {'trash':False}
if province:
filters_steward['province'] = province
kill_house_filterset_class = AllProductsTransportFilterSet
steward = Guilds.objects.filter(**filters_steward, trash=False, is_steward=True).order_by('id')
if search and search != 'undefined' and search.strip():
steward = steward.filter(
build_query(kill_house_filterset_class.Meta.fields, search)
)
steward_codes = steward.values_list('jihadi_code', flat=True)
bars = queryset.filter(
Q(jihadi_origin__in=steward_codes) | Q(jihadi_destination__in=steward_codes)
).order_by('-modify_date')
if destination_province and destination_province != 'undefined':
filters_query['destination_province'] = normalize_persian_arabic_text(destination_province)
bars = bars(**filters_query)
aggregation = bars.aggregate(
total=Sum('quantity'),
input_total=Sum('quantity', filter=Q(out=False)),
output_total=Sum('quantity', filter=Q(out=True)),
input_count=Count('id', filter=Q(out=False)),
output_count=Count('id', filter=Q(out=True)),
total_count=Count('id'),
)
total_count = aggregation['total_count'] or 0
total_quantity = aggregation['total'] or 0
input_quantity = aggregation['input_total'] or 0
output_quantity = aggregation['output_total'] or 0
input_count = aggregation['input_count'] or 0
output_count = aggregation['output_count'] or 0
if total_count > 0 and (input_quantity + output_quantity) > 0:
input_percent = round((input_quantity / (input_quantity + output_quantity)) * 100, 1)
output_percent = round((output_quantity / (input_quantity + output_quantity)) * 100, 1)
else:
input_percent = 0
output_percent = 0
last_update = bars.values_list('modify_date', flat=True).first()
return Response({
"product": product_type,
"bars": int(total_count),
"total_bars_wight": int(total_quantity),
"input_bars": int(input_count),
"total_input_bars_wight": int(input_quantity),
"total_input_bars_percent": input_percent,
"output_bars": int(output_count),
"total_output_bars_wight": int(output_quantity),
"total_output_bars_percent": output_percent,
"total_count_steward": steward.count(),
"last_update": last_update,
}, status=status.HTTP_200_OK)
# if destination_province and destination_province != 'undefined':
# if destination_province == 'مرکزی':
# queryset = queryset.filter(destination_province='مركزي')
# else:
# queryset = queryset.filter(destination_province=destination_province)
aggregation = queryset.aggregate(
total=Sum('quantity'),
input_total=Sum('quantity', filter=Q(out=False)),
output_total=Sum('quantity', filter=Q(out=True)),
input_count=Count('id', filter=Q(out=False)),
output_count=Count('id', filter=Q(out=True)),
total_count=Count('id'),
)
total_count = aggregation['total_count'] or 0
total_quantity = aggregation['total'] or 0
input_quantity = aggregation['input_total'] or 0
output_quantity = aggregation['output_total'] or 0
input_count = aggregation['input_count'] or 0
output_count = aggregation['output_count'] or 0
if total_count > 0 and (input_quantity + output_quantity) > 0:
input_percent = round((input_quantity / (input_quantity + output_quantity)) * 100, 1)
output_percent = round((output_quantity / (input_quantity + output_quantity)) * 100, 1)
else:
input_percent = 0
output_percent = 0
last_update = queryset.order_by('-modify_date').values_list('modify_date', flat=True).first()
return Response({
"role": 'all',
"product": product_type,
"bars": int(total_count),
"total_bars_wight": int(total_quantity),
"input_bars": int(input_count),
"total_input_bars_wight": int(input_quantity),
"total_input_bars_percent": input_percent,
"output_bars": int(output_count),
"total_output_bars_wight": int(output_quantity),
"total_output_bars_percent": output_percent,
"last_update": last_update,
}, status=status.HTTP_200_OK)
class AllProductsTransportProductsListView(APIView):
permission_classes = [AllowAny]
def get(self, request):
products = AllProductsTransport.objects.filter(
trash=False,
product__isnull=False
).exclude(product='').values_list('product', flat=True).distinct().order_by('product')
return Response({
"products": list(products)
}, status=status.HTTP_200_OK)
def _convert_transporting_detail_to_unified(obj):
"""تبدیل TransportingDetail به فرمت یکپارچه"""
hatching_data = None
if obj.hatching:
poultry_data = None
if obj.hatching.poultry:
poultry_data = {
'UnitId': obj.hatching.poultry.UnitId,
'PartIdCode': obj.hatching.poultry.PartIdCode,
'Province': obj.hatching.poultry.Province,
'City': obj.hatching.poultry.City,
'UnitName': obj.hatching.poultry.UnitName,
'Mobile': obj.hatching.poultry.Mobile,
}
hatching_data = {
'PartIdCode': obj.hatching.PartIdCode,
'poultry': poultry_data,
'RequestCode': obj.hatching.RequestCode,
'PedigreeName': obj.hatching.PedigreeName,
}
return {
'id': obj.id,
'key': str(obj.key),
'source': 'TransportingDetail',
'record_id': str(obj.id),
'tracking': obj.TrackingCode,
'date': obj.Date.date() if obj.Date else None,
'product': obj.GoodName,
'items': obj.GoodName,
'quantity': obj.GoodAmount,
'unit': 'قطعه',
'origin_province': obj.hatching.ProvinceName if obj.hatching else None,
'origin_city': obj.hatching.CityName if obj.hatching else None,
'origin': obj.SourceUnitName,
'destination_province': obj.Province,
'destination_city': obj.City,
'destination': obj.DesUnitName,
'jihadi_origin': obj.SourcePartIdCode,
'jihadi_destination': obj.DesPartIdCode,
'owner': obj.hatching.PersonFullName if obj.hatching else None,
'car_tracking_code': None,
'driver_name': None,
'gross_weight': None,
'tare_weight': None,
'net_weight': None,
'scale_code': None,
'scale_name': None,
'scale_receipt': None,
'unloading_date': obj.Date.date() if obj.Date else None,
'unloading': obj.TrackingStatusDescription,
'out': obj.Out,
'hatching': hatching_data,
'create_date': obj.create_date,
'modify_date': obj.modify_date,
}
def _convert_transport_carcass_to_unified(obj):
"""تبدیل TransportCarcassDetail به فرمت یکپارچه"""
return {
'id': obj.id,
'key': str(obj.key),
'source': 'TransportCarcassDetail',
'record_id': obj.id_quarantineh,
'tracking': obj.tracking,
'date': obj.date,
'product': obj.product,
'items': obj.items,
'quantity': obj.quantity,
'unit': obj.unit,
'origin_province': obj.origin_province,
'origin_city': obj.origin_city,
'origin': obj.origin,
'destination_province': obj.destination_province,
'destination_city': obj.destination_city,
'destination': obj.destination,
'jihadi_origin': obj.jihadi_origin,
'jihadi_destination': obj.jihadi_destination,
'owner': obj.owner,
'car_tracking_code': obj.car_tracking_code,
'driver_name': obj.driver_name,
'gross_weight': obj.gross_weight,
'tare_weight': obj.tare_weight,
'net_weight': obj.net_weight,
'scale_code': obj.scale_code,
'scale_name': obj.scale_name,
'scale_receipt': obj.scale_receipt,
'unloading_date': obj.unloading_date,
'unloading': obj.unloading,
'out': obj.out,
'hatching': None,
'create_date': obj.create_date,
'modify_date': obj.modify_date,
}
def _convert_all_products_to_unified(obj):
"""تبدیل AllProductsTransport به فرمت یکپارچه"""
hatching_data = None
if obj.hatching:
poultry_data = None
if obj.hatching.poultry:
poultry_data = {
'UnitId': obj.hatching.poultry.UnitId,
'PartIdCode': obj.hatching.poultry.PartIdCode,
'Province': obj.hatching.poultry.Province,
'City': obj.hatching.poultry.City,
'UnitName': obj.hatching.poultry.UnitName,
'Mobile': obj.hatching.poultry.Mobile,
}
hatching_data = {
'PartIdCode': obj.hatching.PartIdCode,
'poultry': poultry_data,
'RequestCode': obj.hatching.RequestCode,
'PedigreeName': obj.hatching.PedigreeName,
}
return {
'id': obj.id,
'key': str(obj.key),
'source': 'AllProductsTransport',
'record_id': obj.record_id,
'tracking': obj.tracking,
'date': obj.date,
'product': obj.product,
'items': obj.items,
'quantity': obj.quantity,
'unit': obj.unit,
'origin_province': obj.origin_province,
'origin_city': obj.origin_city,
'origin': obj.origin,
'destination_province': obj.destination_province,
'destination_city': obj.destination_city,
'destination': obj.destination,
'jihadi_origin': obj.jihadi_origin,
'jihadi_destination': obj.jihadi_destination,
'owner': obj.owner,
'car_tracking_code': obj.car_tracking_code,
'driver_name': obj.driver_name,
'gross_weight': obj.gross_weight,
'tare_weight': obj.tare_weight,
'net_weight': obj.net_weight,
'scale_code': obj.scale_code,
'scale_name': obj.scale_name,
'scale_receipt': obj.scale_receipt,
'unloading_date': obj.unloading_date,
'unloading': obj.unloading,
'out': obj.out,
'hatching': hatching_data,
'create_date': obj.create_date,
'modify_date': obj.modify_date,
}
@api_view(['GET'])
@permission_classes([AllowAny])
@csrf_exempt
def get_all_products_transport_by_code(request):
code = request.GET.get('code')
if not code:
return Response(
{'detail': 'کد الزامی است'},
status=status.HTTP_400_BAD_REQUEST
)
transport_type = request.GET.get('type')
if transport_type not in ['in', 'out']:
return Response(
{'detail': 'نوع باید in یا out باشد'},
status=status.HTTP_400_BAD_REQUEST
)
from_source = request.GET.get('from')
if from_source and from_source not in ['Poultry', 'KillHouse']:
return Response(
{'detail': 'from باید Poultry یا KillHouse باشد'},
status=status.HTTP_400_BAD_REQUEST
)
date1 = request.GET.get('date1')
date2 = request.GET.get('date2')
start_date = None
end_date = None
if date1 and date2 and date1 != 'undefined' and date2 != 'undefined':
try:
start_date = datetime.datetime.strptime(str(date1), '%Y-%m-%d')
end_date = datetime.datetime.strptime(str(date2), '%Y-%m-%d')
except ValueError:
pass
province = request.GET.get('province')
product_type = request.GET.get('product')
search = request.GET.get('search')
unified_results = []
seen_tracking_codes = set()
def add_if_not_duplicate(item):
tracking = item.get('tracking')
if tracking and tracking in seen_tracking_codes:
return False
if tracking:
seen_tracking_codes.add(tracking)
unified_results.append(item)
return True
if from_source == 'Poultry':
if transport_type == 'out':
all_products = AllProductsTransport.objects.filter(
trash=False,
jihadi_origin=code,
)
if start_date and end_date:
all_products = all_products.filter(date__gte=start_date, date__lte=end_date)
if province and province != 'undefined':
all_products = all_products.filter(destination_province=province)
if product_type and product_type != 'undefined':
all_products = all_products.filter(product=product_type)
for obj in all_products:
add_if_not_duplicate(_convert_all_products_to_unified(obj))
transport_details = TransportingDetail.objects.filter(
trash=False,
hatching__poultry__PartIdCode=code,
TrackingStatusDescription__in=(
'تایید تخلیه', 'بارگیری')).order_by('-Date')
if start_date and end_date:
transport_details = transport_details.filter(Date__gte=start_date, Date__lte=end_date)
if province and province != 'undefined':
transport_details = transport_details.filter(Province=province)
for obj in transport_details:
add_if_not_duplicate(_convert_transporting_detail_to_unified(obj))
else:
all_products = AllProductsTransport.objects.filter(
trash=False,
jihadi_destination=code
).order_by('-date')
if start_date and end_date:
all_products = all_products.filter(date__gte=start_date, date__lte=end_date)
if province and province != 'undefined':
all_products = all_products.filter(origin_province=province)
if product_type and product_type != 'undefined':
all_products = all_products.filter(product=product_type)
for obj in all_products:
add_if_not_duplicate(_convert_all_products_to_unified(obj))
elif from_source == 'KillHouse':
if transport_type == 'out':
carcass_details = TransportCarcassDetail.objects.filter(
trash=False,
jihadi_origin=code,
)
if start_date and end_date:
carcass_details = carcass_details.filter(date__gte=start_date, date__lte=end_date)
if province and province != 'undefined':
carcass_details = carcass_details.filter(destination_province=province)
if product_type and product_type != 'undefined':
carcass_details = carcass_details.filter(product=product_type)
for obj in carcass_details:
add_if_not_duplicate(_convert_transport_carcass_to_unified(obj))
else:
transport_details = TransportingDetail.objects.filter(
trash=False,
DesPartIdCode=code,
TrackingStatusDescription__in=(
'تایید تخلیه', 'بارگیری')).select_related('hatching', 'hatching__poultry')
if start_date and end_date:
transport_details = transport_details.filter(Date__gte=start_date, Date__lte=end_date)
if province and province != 'undefined':
transport_details = transport_details.filter(hatching__ProvinceName=province)
for obj in transport_details:
add_if_not_duplicate(_convert_transporting_detail_to_unified(obj))
else:
if transport_type == 'out':
bars = AllProductsTransport.objects.filter(
trash=False,
jihadi_origin=code
)
else:
bars = AllProductsTransport.objects.filter(
trash=False,
jihadi_destination=code
)
if start_date and end_date:
bars = bars.filter(date__gte=start_date, date__lte=end_date)
if province and province != 'undefined':
if transport_type == 'out':
bars = bars.filter(destination_province=province)
else:
bars = bars.filter(origin_province=province)
if product_type and product_type != 'undefined':
bars = bars.filter(product=product_type)
for obj in bars:
add_if_not_duplicate(_convert_all_products_to_unified(obj))
if search and search != 'undefined' and search.strip():
search_lower = search.lower()
unified_results = [
r for r in unified_results
if (r.get('tracking') and search_lower in str(r['tracking']).lower()) or
(r.get('product') and search_lower in str(r['product']).lower()) or
(r.get('origin') and search_lower in str(r['origin']).lower()) or
(r.get('destination') and search_lower in str(r['destination']).lower()) or
(r.get('driver_name') and search_lower in str(r['driver_name']).lower()) or
(r.get('owner') and search_lower in str(r['owner']).lower())
]
unified_results.sort(key=lambda x: x.get('date') or datetime.date.min, reverse=True)
paginator = CustomPagination()
page_size = request.query_params.get('page_size', None)
if page_size:
paginator.page_size = int(page_size)
page_number = int(request.query_params.get('page', 1))
start_index = (page_number - 1) * paginator.page_size
end_index = start_index + paginator.page_size
paginated_results = unified_results[start_index:end_index]
return Response({
'count': len(unified_results),
'next': f"?page={page_number + 1}" if end_index < len(unified_results) else None,
'previous': f"?page={page_number - 1}" if page_number > 1 else None,
'results': paginated_results
}, status=status.HTTP_200_OK)
@api_view(['GET'])
@permission_classes([AllowAny])
@csrf_exempt
def get_all_products_transport_products_by_code(request):
code = request.GET.get('code')
if not code:
return Response(
{'detail': 'کد الزامی است'},
status=status.HTTP_400_BAD_REQUEST
)
transport_type = request.GET.get('type')
if transport_type not in ['in', 'out']:
return Response(
{'detail': 'نوع باید in یا out باشد'},
status=status.HTTP_400_BAD_REQUEST
)
from_source = request.GET.get('from')
if from_source and from_source not in ['Poultry', 'KillHouse']:
return Response(
{'detail': 'from باید Poultry یا KillHouse باشد'},
status=status.HTTP_400_BAD_REQUEST
)
date1 = request.GET.get('date1')
date2 = request.GET.get('date2')
start_date = None
end_date = None
if date1 and date2 and date1 != 'undefined' and date2 != 'undefined':
try:
start_date = datetime.datetime.strptime(str(date1), '%Y-%m-%d')
end_date = datetime.datetime.strptime(str(date2), '%Y-%m-%d')
except ValueError:
pass
province = request.GET.get('province')
product_type = request.GET.get('product')
search = request.GET.get('search')
products_set = set()
if from_source == 'Poultry':
if transport_type == 'out':
all_products = AllProductsTransport.objects.filter(
trash=False,
jihadi_origin=code,
)
if start_date and end_date:
all_products = all_products.filter(date__gte=start_date, date__lte=end_date)
if province and province != 'undefined':
all_products = all_products.filter(destination_province=province)
if product_type and product_type != 'undefined':
all_products = all_products.filter(product=product_type)
products_set.update(
all_products.filter(product__isnull=False)
.exclude(product='')
.values_list('product', flat=True)
.distinct()
)
transport_details = TransportingDetail.objects.filter(
trash=False,
hatching__poultry__PartIdCode=code,
TrackingStatusDescription__in=('تایید تخلیه', 'بارگیری')
).select_related('hatching', 'hatching__poultry')
if start_date and end_date:
transport_details = transport_details.filter(Date__gte=start_date, Date__lte=end_date)
if province and province != 'undefined':
transport_details = transport_details.filter(Province=province)
products_set.update(
transport_details.filter(GoodName__isnull=False)
.exclude(GoodName='')
.values_list('GoodName', flat=True)
.distinct()
)
else:
all_products = AllProductsTransport.objects.filter(
trash=False,
jihadi_destination=code
)
if start_date and end_date:
all_products = all_products.filter(date__gte=start_date, date__lte=end_date)
if province and province != 'undefined':
all_products = all_products.filter(origin_province=province)
if product_type and product_type != 'undefined':
all_products = all_products.filter(product=product_type)
products_set.update(
all_products.filter(product__isnull=False)
.exclude(product='')
.values_list('product', flat=True)
.distinct()
)
elif from_source == 'KillHouse':
if transport_type == 'out':
carcass_details = TransportCarcassDetail.objects.filter(
trash=False,
jihadi_origin=code,
)
if start_date and end_date:
carcass_details = carcass_details.filter(date__gte=start_date, date__lte=end_date)
if province and province != 'undefined':
carcass_details = carcass_details.filter(destination_province=province)
if product_type and product_type != 'undefined':
carcass_details = carcass_details.filter(product=product_type)
products_set.update(
carcass_details.filter(product__isnull=False)
.exclude(product='')
.values_list('product', flat=True)
.distinct()
)
else:
transport_details = TransportingDetail.objects.filter(
trash=False,
DesPartIdCode=code,
TrackingStatusDescription__in=('تایید تخلیه', 'بارگیری')
).select_related('hatching', 'hatching__poultry')
if start_date and end_date:
transport_details = transport_details.filter(Date__gte=start_date, Date__lte=end_date)
if province and province != 'undefined':
transport_details = transport_details.filter(hatching__ProvinceName=province)
products_set.update(
transport_details.filter(GoodName__isnull=False)
.exclude(GoodName='')
.values_list('GoodName', flat=True)
.distinct()
)
else:
if transport_type == 'out':
bars = AllProductsTransport.objects.filter(
trash=False,
jihadi_origin=code
)
else:
bars = AllProductsTransport.objects.filter(
trash=False,
jihadi_destination=code
)
if start_date and end_date:
bars = bars.filter(date__gte=start_date, date__lte=end_date)
if province and province != 'undefined':
if transport_type == 'out':
bars = bars.filter(destination_province=province)
else:
bars = bars.filter(origin_province=province)
if product_type and product_type != 'undefined':
bars = bars.filter(product=product_type)
products_set.update(
bars.filter(product__isnull=False)
.exclude(product='')
.values_list('product', flat=True)
.distinct()
)
if search and search != 'undefined' and search.strip():
search_lower = search.lower()
products_set = {
p for p in products_set
if p and search_lower in str(p).lower()
}
products = sorted([p for p in products_set if p], key=str)
return Response({
"products": products
}, status=status.HTTP_200_OK)
@api_view(['GET'])
@permission_classes([AllowAny])
@csrf_exempt
def get_all_products_transport_provinces_by_code(request):
code = request.GET.get('code')
if not code:
return Response(
{'detail': 'کد الزامی است'},
status=status.HTTP_400_BAD_REQUEST
)
transport_type = request.GET.get('type')
if transport_type not in ['in', 'out']:
return Response(
{'detail': 'نوع باید in یا out باشد'},
status=status.HTTP_400_BAD_REQUEST
)
from_source = request.GET.get('from')
if from_source and from_source not in ['Poultry', 'KillHouse']:
return Response(
{'detail': 'from باید Poultry یا KillHouse باشد'},
status=status.HTTP_400_BAD_REQUEST
)
date1 = request.GET.get('date1')
date2 = request.GET.get('date2')
start_date = None
end_date = None
if date1 and date2 and date1 != 'undefined' and date2 != 'undefined':
try:
start_date = datetime.datetime.strptime(str(date1), '%Y-%m-%d')
end_date = datetime.datetime.strptime(str(date2), '%Y-%m-%d')
except ValueError:
pass
province = request.GET.get('province')
product_type = request.GET.get('product')
search = request.GET.get('search')
provinces_set = set()
if from_source == 'Poultry':
if transport_type == 'out':
all_products = AllProductsTransport.objects.filter(
trash=False,
jihadi_origin=code,
)
if start_date and end_date:
all_products = all_products.filter(date__gte=start_date, date__lte=end_date)
if province and province != 'undefined':
all_products = all_products.filter(destination_province=province)
if product_type and product_type != 'undefined':
all_products = all_products.filter(product=product_type)
provinces_set.update(
all_products.filter(destination_province__isnull=False)
.exclude(destination_province='')
.values_list('destination_province', flat=True)
.distinct()
)
transport_details = TransportingDetail.objects.filter(
trash=False,
hatching__poultry__PartIdCode=code,
TrackingStatusDescription__in=('تایید تخلیه', 'بارگیری')
).select_related('hatching', 'hatching__poultry')
if start_date and end_date:
transport_details = transport_details.filter(Date__gte=start_date, Date__lte=end_date)
if province and province != 'undefined':
transport_details = transport_details.filter(Province=province)
provinces_set.update(
transport_details.filter(Province__isnull=False)
.exclude(Province='')
.values_list('Province', flat=True)
.distinct()
)
else:
all_products = AllProductsTransport.objects.filter(
trash=False,
jihadi_destination=code
)
if start_date and end_date:
all_products = all_products.filter(date__gte=start_date, date__lte=end_date)
if province and province != 'undefined':
all_products = all_products.filter(origin_province=province)
if product_type and product_type != 'undefined':
all_products = all_products.filter(product=product_type)
provinces_set.update(
all_products.filter(origin_province__isnull=False)
.exclude(origin_province='')
.values_list('origin_province', flat=True)
.distinct()
)
elif from_source == 'KillHouse':
if transport_type == 'out':
carcass_details = TransportCarcassDetail.objects.filter(
trash=False,
jihadi_origin=code,
)
if start_date and end_date:
carcass_details = carcass_details.filter(date__gte=start_date, date__lte=end_date)
if province and province != 'undefined':
carcass_details = carcass_details.filter(destination_province=province)
if product_type and product_type != 'undefined':
carcass_details = carcass_details.filter(product=product_type)
provinces_set.update(
carcass_details.filter(destination_province__isnull=False)
.exclude(destination_province='')
.values_list('destination_province', flat=True)
.distinct()
)
else:
transport_details = TransportingDetail.objects.filter(
trash=False,
DesPartIdCode=code,
TrackingStatusDescription__in=('تایید تخلیه', 'بارگیری')
).select_related('hatching', 'hatching__poultry')
if start_date and end_date:
transport_details = transport_details.filter(Date__gte=start_date, Date__lte=end_date)
if province and province != 'undefined':
transport_details = transport_details.filter(hatching__ProvinceName=province)
provinces_set.update(
transport_details.filter(hatching__ProvinceName__isnull=False)
.exclude(hatching__ProvinceName='')
.values_list('hatching__ProvinceName', flat=True)
.distinct()
)
else:
if transport_type == 'out':
bars = AllProductsTransport.objects.filter(
trash=False,
jihadi_origin=code
)
else:
bars = AllProductsTransport.objects.filter(
trash=False,
jihadi_destination=code
)
if start_date and end_date:
bars = bars.filter(date__gte=start_date, date__lte=end_date)
if province and province != 'undefined':
if transport_type == 'out':
bars = bars.filter(destination_province=province)
else:
bars = bars.filter(origin_province=province)
if product_type and product_type != 'undefined':
bars = bars.filter(product=product_type)
if transport_type == 'out':
provinces_set.update(
bars.filter(destination_province__isnull=False)
.exclude(destination_province='')
.values_list('destination_province', flat=True)
.distinct()
)
else:
provinces_set.update(
bars.filter(origin_province__isnull=False)
.exclude(origin_province='')
.values_list('origin_province', flat=True)
.distinct()
)
if search and search != 'undefined' and search.strip():
search_lower = search.lower()
provinces_set = {
p for p in provinces_set
if p and search_lower in str(p).lower()
}
provinces = sorted([p for p in provinces_set if p], key=str)
return Response({
"provinces": provinces
}, status=status.HTTP_200_OK)
@api_view(['GET'])
@permission_classes([AllowAny])
@csrf_exempt
def get_all_products_transport_dashboard_by_code(request):
code = request.GET.get('code')
if not code:
return Response(
{'detail': 'کد الزامی است'},
status=status.HTTP_400_BAD_REQUEST
)
transport_type = request.GET.get('type')
if transport_type not in ['in', 'out']:
return Response(
{'detail': 'نوع باید in یا out باشد'},
status=status.HTTP_400_BAD_REQUEST
)
from_source = request.GET.get('from')
if from_source and from_source not in ['Poultry', 'KillHouse']:
return Response(
{'detail': 'from باید Poultry یا KillHouse باشد'},
status=status.HTTP_400_BAD_REQUEST
)
date1 = request.GET.get('date1')
date2 = request.GET.get('date2')
start_date = None
end_date = None
if date1 and date2 and date1 != 'undefined' and date2 != 'undefined':
try:
start_date = datetime.datetime.strptime(str(date1), '%Y-%m-%d')
end_date = datetime.datetime.strptime(str(date2), '%Y-%m-%d')
except ValueError:
pass
province = request.GET.get('province')
product_type = request.GET.get('product')
search = request.GET.get('search')
total_count = 0
total_quantity = 0
input_quantity = 0
output_quantity = 0
input_count = 0
output_count = 0
last_update = None
if from_source == 'Poultry':
if transport_type == 'out':
all_products = AllProductsTransport.objects.filter(
trash=False,
jihadi_origin=code,
)
if start_date and end_date:
all_products = all_products.filter(date__gte=start_date, date__lte=end_date)
if province and province != 'undefined':
all_products = all_products.filter(destination_province=province)
if product_type and product_type != 'undefined':
all_products = all_products.filter(product=product_type)
agg = all_products.aggregate(
total=Sum('quantity'),
input_total=Sum('quantity', filter=Q(out=False)),
output_total=Sum('quantity', filter=Q(out=True)),
input_cnt=Count('id', filter=Q(out=False)),
output_cnt=Count('id', filter=Q(out=True)),
total_cnt=Count('id'),
last_mod=Max('modify_date'),
)
total_count += agg['total_cnt'] or 0
total_quantity += agg['total'] or 0
input_quantity += agg['input_total'] or 0
output_quantity += agg['output_total'] or 0
input_count += agg['input_cnt'] or 0
output_count += agg['output_cnt'] or 0
if agg['last_mod'] and (not last_update or agg['last_mod'] > last_update):
last_update = agg['last_mod']
transport_details = TransportingDetail.objects.filter(
trash=False,
hatching__poultry__PartIdCode=code,
TrackingStatusDescription__in=('تایید تخلیه', 'بارگیری')
).select_related('hatching', 'hatching__poultry')
if start_date and end_date:
transport_details = transport_details.filter(Date__gte=start_date, Date__lte=end_date)
if province and province != 'undefined':
transport_details = transport_details.filter(Province=province)
agg = transport_details.aggregate(
total=Sum('GoodAmount'),
input_total=Sum('GoodAmount', filter=Q(Out=False)),
output_total=Sum('GoodAmount', filter=Q(Out=True)),
input_cnt=Count('id', filter=Q(Out=False)),
output_cnt=Count('id', filter=Q(Out=True)),
total_cnt=Count('id'),
last_mod=Max('modify_date'),
)
total_count += agg['total_cnt'] or 0
total_quantity += agg['total'] or 0
input_quantity += agg['input_total'] or 0
output_quantity += agg['output_total'] or 0
input_count += agg['input_cnt'] or 0
output_count += agg['output_cnt'] or 0
if agg['last_mod'] and (not last_update or agg['last_mod'] > last_update):
last_update = agg['last_mod']
else:
all_products = AllProductsTransport.objects.filter(
trash=False,
jihadi_destination=code
)
if start_date and end_date:
all_products = all_products.filter(date__gte=start_date, date__lte=end_date)
if province and province != 'undefined':
all_products = all_products.filter(origin_province=province)
if product_type and product_type != 'undefined':
all_products = all_products.filter(product=product_type)
agg = all_products.aggregate(
total=Sum('quantity'),
input_total=Sum('quantity', filter=Q(out=False)),
output_total=Sum('quantity', filter=Q(out=True)),
input_cnt=Count('id', filter=Q(out=False)),
output_cnt=Count('id', filter=Q(out=True)),
total_cnt=Count('id'),
last_mod=Max('modify_date'),
)
total_count += agg['total_cnt'] or 0
total_quantity += agg['total'] or 0
input_quantity += agg['input_total'] or 0
output_quantity += agg['output_total'] or 0
input_count += agg['input_cnt'] or 0
output_count += agg['output_cnt'] or 0
if agg['last_mod'] and (not last_update or agg['last_mod'] > last_update):
last_update = agg['last_mod']
elif from_source == 'KillHouse':
if transport_type == 'out':
carcass_details = TransportCarcassDetail.objects.filter(
trash=False,
jihadi_origin=code,
)
if start_date and end_date:
carcass_details = carcass_details.filter(date__gte=start_date, date__lte=end_date)
if province and province != 'undefined':
carcass_details = carcass_details.filter(destination_province=province)
if product_type and product_type != 'undefined':
carcass_details = carcass_details.filter(product=product_type)
agg = carcass_details.aggregate(
total=Sum('quantity'),
input_total=Sum('quantity', filter=Q(out=False)),
output_total=Sum('quantity', filter=Q(out=True)),
input_cnt=Count('id', filter=Q(out=False)),
output_cnt=Count('id', filter=Q(out=True)),
total_cnt=Count('id'),
last_mod=Max('modify_date'),
)
total_count += agg['total_cnt'] or 0
total_quantity += agg['total'] or 0
input_quantity += agg['input_total'] or 0
output_quantity += agg['output_total'] or 0
input_count += agg['input_cnt'] or 0
output_count += agg['output_cnt'] or 0
if agg['last_mod'] and (not last_update or agg['last_mod'] > last_update):
last_update = agg['last_mod']
else:
transport_details = TransportingDetail.objects.filter(
trash=False,
DesPartIdCode=code,
TrackingStatusDescription__in=('تایید تخلیه', 'بارگیری')
).select_related('hatching', 'hatching__poultry')
if start_date and end_date:
transport_details = transport_details.filter(Date__gte=start_date, Date__lte=end_date)
if province and province != 'undefined':
transport_details = transport_details.filter(hatching__ProvinceName=province)
agg = transport_details.aggregate(
total=Sum('GoodAmount'),
input_total=Sum('GoodAmount', filter=Q(Out=False)),
output_total=Sum('GoodAmount', filter=Q(Out=True)),
input_cnt=Count('id', filter=Q(Out=False)),
output_cnt=Count('id', filter=Q(Out=True)),
total_cnt=Count('id'),
last_mod=Max('modify_date'),
)
total_count += agg['total_cnt'] or 0
total_quantity += agg['total'] or 0
input_quantity += agg['input_total'] or 0
output_quantity += agg['output_total'] or 0
input_count += agg['input_cnt'] or 0
output_count += agg['output_cnt'] or 0
if agg['last_mod'] and (not last_update or agg['last_mod'] > last_update):
last_update = agg['last_mod']
else:
if transport_type == 'out':
all_bars = AllProductsTransport.objects.filter(
trash=False,
jihadi_origin=code
)
else:
all_bars = AllProductsTransport.objects.filter(
trash=False,
jihadi_destination=code
)
if start_date and end_date:
all_bars = all_bars.filter(date__gte=start_date, date__lte=end_date)
if province and province != 'undefined':
if transport_type == 'out':
all_bars = all_bars.filter(destination_province=province)
else:
all_bars = all_bars.filter(origin_province=province)
if product_type and product_type != 'undefined':
all_bars = all_bars.filter(product=product_type)
if search and search != 'undefined' and search.strip():
all_bars = all_bars.filter(
build_query(AllProductsTransportFilterSet.Meta.fields, search)
)
aggregation = all_bars.aggregate(
total=Sum('quantity'),
input_total=Sum('quantity', filter=Q(out=False)),
output_total=Sum('quantity', filter=Q(out=True)),
input_count=Count('id', filter=Q(out=False)),
output_count=Count('id', filter=Q(out=True)),
total_count=Count('id'),
last_mod=Max('modify_date'),
)
total_count = aggregation['total_count'] or 0
total_quantity = aggregation['total'] or 0
input_quantity = aggregation['input_total'] or 0
output_quantity = aggregation['output_total'] or 0
input_count = aggregation['input_count'] or 0
output_count = aggregation['output_count'] or 0
last_update = aggregation['last_mod']
if total_count > 0 and (input_quantity + output_quantity) > 0:
input_percent = round((input_quantity / (input_quantity + output_quantity)) * 100, 1)
output_percent = round((output_quantity / (input_quantity + output_quantity)) * 100, 1)
else:
input_percent = 0
output_percent = 0
return Response({
"bars": int(total_count),
"input_bars": int(input_count),
"last_update": last_update,
"output_bars": int(output_count),
"product": product_type,
"role": "all",
"total_bars_wight": int(total_quantity),
"total_input_bars_percent": input_percent,
"total_input_bars_wight": int(input_quantity),
"total_output_bars_percent": output_percent,
"total_output_bars_wight": int(output_quantity),
}, status=status.HTTP_200_OK)
@api_view(['POST'])
@permission_classes([AllowAny])
@csrf_exempt
def get_ai_response(request):
result_data = {}
models_info = request.data.get('models_info')
for model_info in models_info:
model_name = model_info.get("model")
filters = model_info.get("filters", {})
aggregations = model_info.get("aggregations") or []
fields_to_return = model_info.get("fields_to_return") or []
date_filter = model_info.get("date_filter")
if model_name == "Hatching":
queryset = Hatching.objects.filter(**filters)
elif model_name == "Poultry":
queryset = Poultry.objects.filter(**filters)
else:
continue
queryset = apply_date_filter(queryset, date_filter)
model_result = {}
if "count" in aggregations:
model_result["count"] = queryset.count()
if "sum" in aggregations:
model_result["sum"] = (
queryset.aggregate(total=Sum("ChickCountSum"))["total"] or 0
)
if fields_to_return:
descriptive_data = queryset.values(*fields_to_return).first()
if descriptive_data:
model_result.update(descriptive_data)
result_data[model_name] = model_result
return Response(
{
"data": result_data
},
status=status.HTTP_200_OK
)