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 = { 'آربراکرز (آ��لاس)': 'آربراکرز (آپلاس)', 'آربراک��ز (آپلاس)': 'آربراکرز (آپلاس)', 'آربر��کرز (آپلاس)': 'آربراکرز (آپلاس)', 'را��': 'راس', 'ر��س': 'راس', '��اس': 'راس', 'آ��ین': 'آرین', 'آر��ن': 'آرین', 'ایندین ریو��': 'ایندین ریور', 'ایند��ن ریور': 'ایندین ریور', 'ک��ب': 'کاب' } # 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(): setattr(poultry, key, value) poultry.save() # 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 = { 'آربراکرز (آ��لاس)': 'آربراکرز (آپلاس)', 'آربراک��ز (آپلاس)': 'آربراکرز (آپلاس)', 'آربر��کرز (آپلاس)': 'آربراکرز (آپلاس)', 'را��': 'راس', 'ر��س': 'راس', '��اس': 'راس', 'آ��ین': 'آرین', 'آر��ن': 'آرین', 'ایندین ریو��': 'ایندین ریور', 'ایند��ن ریور': 'ایندین ریور', 'ک��ب': 'کاب' } 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 = { 'آربراکرز (آ��لاس)': 'آربراکرز (آپلاس)', 'آربراک��ز (آپلاس)': 'آربراکرز (آپلاس)', 'آربر��کرز (آپلاس)': 'آربراکرز (آپلاس)', 'را��': 'راس', 'ر��س': 'راس', '��اس': 'راس', 'آ��ین': 'آرین', 'آر��ن': 'آرین', 'ایندین ریو��': 'ایندین ریور', 'ایند��ن ریور': 'ایندین ریور', 'ک��ب': 'کاب' } 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 )