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