Files
Rasadyar_Marzaki/pdf/views.py
2026-01-18 11:45:53 +03:30

1636 lines
83 KiB
Python

import datetime
import io
from urllib.parse import quote
import requests
from django.db.models import Sum, Count, Avg, Q
from django.http import HttpResponse
from django.template.loader import render_to_string
from weasyprint import HTML, CSS
from weasyprint.text.fonts import FontConfiguration
from general_urls import base_url_for_sms_report
from panel.KillHouse.helpers import get_finance_info, check_kill_house_remain_limitation_weight
from django.db.models import F
from panel.KillHouse.serializers import KillHouseRequestForHatchingDetailSerializer, \
KillHouseRequestForBarManagementSerializer, ReturnProvinceKillRequestSerializer, BarDifferenceRequestSerializer
from panel.helper_excel import shamsi_date, to_locale_str
from panel.models import KillRequest, ProvinceKillRequest, PoultryHatching, KillHouseRequest, \
KillHouseFreeBarInformation, KillHouse, StewardAllocation, KillHouseFreeSaleBarInformation, RolesProducts, \
DirectBuyingPayment, PoultryRequest, ChainAllocation, BarDifferenceRequest, HatchingIncreaseRequest, \
PoultryScienceReport, KillHousePurchaseRequest, InternalTransaction, PosSegmentation, WarehouseArchive, \
Guilds, StewardFreeBarInformation, StewardFreeSaleBarInformation
from panel.poultry.serializers import PoultryHatchingForDetailsSerializer, PoultryRequestForHatchingDetailSerializer, \
ChainAllocationForHatchingDetailSerializer, HatchingIncreaseRequestSerializer, EvacuationHatchingDetailSerializer
def kill_request_pdf(request):
font_config = FontConfiguration()
kill_request = KillRequest.objects.filter(trash=False, key=request.GET['key']).select_related(
'kill_house', 'poultry', 'poultry__address', 'poultry__user', 'kill_house__kill_house_operator'
).only(
'poultry__unit_name',
'poultry__user__fullname',
'poultry__user__mobile',
'poultry__user__national_code',
'poultry__breeding_unique_id',
'poultry__breeding_unique_id',
'poultry__address__address',
'poultry__user__city__name',
'kill_house__kill_house_operator__user__fullname',
'kill_house__kill_house_operator__user__national_code',
'kill_house__kill_house_operator__address__address',
'kill_house__kill_house_operator__user__city__name',
'kill_house__name',
'kill_capacity',
'amount',
'recive_date',
'Index_weight',
'input_direct_buying_code',
'direct_buying_state',
'poultry_hatching__chicken_age',
'poultry_hatching__licence_number',
'payment_deadline_date',
'payment_deadline_days',
'direct_buying_intermediary_mobile',
).first()
recive_date = kill_request.recive_date
if isinstance(recive_date, str):
try:
recive_date = datetime.datetime.strptime(recive_date, '%Y-%m-%dT%H:%M:%S.%f')
except ValueError:
recive_date = datetime.datetime.strptime(recive_date, '%Y-%m-%dT%H:%M:%S')
date = shamsi_date(recive_date.date(), in_value=True)
date_in_value = shamsi_date(recive_date.date())
if kill_request.market_state == 'accepted' or kill_request.input_direct_buying_code or \
kill_request.direct_buying_state == 'accepted':
input_direct_buying_code = True
else:
input_direct_buying_code = False
if kill_request.market_final_accept or kill_request.final_accept:
final_accept = True
else:
final_accept = False
if kill_request.kill_house.kill_house_operator.address.address is not None:
kill_house_address = kill_request.kill_house.kill_house_operator.address.address
elif kill_request.kill_house.kill_house_operator.user.city.name:
kill_house_address = kill_request.kill_house.kill_house_operator.user.city.name
else:
kill_house_address = '-'
if kill_request.poultry.address.address:
poultry_address = kill_request.poultry.address.address
elif kill_request.poultry.user.city.name:
poultry_address = kill_request.poultry.user.city.name
else:
poultry_address = '-'
kill_house_request = KillHouseRequest.objects.filter(trash=False, kill_request=kill_request,
assignment_state_archive='True').aggregate(
total_quantity=Sum('accepted_real_quantity'),
total_weight=Sum('accepted_real_weight'),
)
province_kill_req = ProvinceKillRequest.objects.filter(trash=False, kill_request=kill_request).only(
'province_request__poultry_request__order_code'
).first()
payments = DirectBuyingPayment.objects.filter(province_kill_request=province_kill_req, trash=False)
total_paid_amount = payments.aggregate(total=Sum('amount'))['total'] or 0
avg_killed_weight = round((kill_house_request['total_weight'] or 0) / (kill_house_request['total_quantity'] or 0)
if (kill_house_request['total_quantity'] or 0) > 0 else 0,
1)
html_content = render_to_string('Digital_agreement_for_buying_and_selling.html', { # noqa
'date': date,
'unit_name': kill_request.poultry.unit_name,
'fullname': kill_request.poultry.user.fullname,
'mobile': kill_request.poultry.user.mobile,
'national_code': kill_request.poultry.user.national_code if kill_request.poultry.user.national_code else '-',
'breeding_unique_id': kill_request.poultry.breeding_unique_id if
kill_request.poultry.breeding_unique_id else '-',
'poultry_address': poultry_address,
'kill_house_fullname': kill_request.kill_house.kill_house_operator.user.fullname,
'kill_house_name': kill_request.kill_house.name,
'kill_house_national_code': kill_request.kill_house.kill_house_operator.user.national_code if
kill_request.kill_house.kill_house_operator.user.national_code else '-',
'kill_house_mobile': kill_request.kill_house.kill_house_operator.user.mobile,
'kill_house_address': kill_house_address,
'kill_capacity': to_locale_str(kill_request.kill_capacity),
'date_in_value': date_in_value,
'amount': to_locale_str(int(kill_request.amount)),
'weight': to_locale_str(round(kill_request.Index_weight * kill_request.kill_capacity, 1)),
'input_direct_buying_code': input_direct_buying_code,
'direct_buying_state': final_accept,
'Index_weight': kill_request.Index_weight,
'chicken_age': kill_request.poultry_hatching.chicken_age,
'licence_number': kill_request.poultry_hatching.licence_number if
kill_request.poultry_hatching.licence_number else '-',
'max_time': shamsi_date(kill_request.payment_deadline_date) if kill_request.payment_deadline_date else '-',
'payment_deadline_days': kill_request.payment_deadline_days,
'number': province_kill_req.province_request.poultry_request.order_code if province_kill_req else '-',
'total_killed_quantity': to_locale_str(kill_house_request['total_quantity'] or 0),
'total_killed_weight': to_locale_str(kill_house_request['total_weight'] or 0),
'avg_killed_weight': avg_killed_weight,
'direct_buying_intermediary_mobile': kill_request.direct_buying_intermediary_mobile,
'payment_deadline_state': province_kill_req.payment_deadline_state,
'total_paid_amount': to_locale_str(total_paid_amount),
'payment_deadline_checker_fullname': province_kill_req.payment_deadline_checker_fullname,
'payment_deadline_check_date': shamsi_date(province_kill_req.payment_deadline_check_date) \
if province_kill_req.payment_deadline_check_date else '-',
'payment_deadline_archive_message': province_kill_req.payment_deadline_archive_message,
})
html = HTML(string=html_content, base_url=request.build_absolute_uri()) # noqa
css = CSS(string='''
''', font_config=font_config)
pdf_file = io.BytesIO()
html.write_pdf(pdf_file, stylesheets=[css], font_config=font_config)
pdf_file.seek(0)
response = HttpResponse(pdf_file, content_type='application/pdf')
filename = 'توافق‌نامه {0}.pdf'.format(
province_kill_req.province_request.poultry_request.order_code if province_kill_req else "-")
encoded_filename = quote(filename) # کدگذاری نام فایل برای URL
response['Content-Disposition'] = f'attachment; filename*=UTF-8\'\'{encoded_filename}'
return response
def management_all_poultry_and_warehouse_pdf(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()
poultry_hatching = PoultryHatching.objects.filter(Q(date__date__gte=date1, date__date__lte=date2) |
Q(date__date__lte=date1,
archive_date__isnull=True) | Q(date__date__lte=date1,
archive_date__gte=date1,
archive_date__isnull=False),
trash=False).select_related('poultry', 'poultry__user__city')
kill_house_request = KillHouseRequest.objects.filter(
trash=False,
kill_request__recive_date__date__gte=date1,
kill_request__recive_date__date__lte=date2,
temporary_trash=False,
temporary_deleted=False
).select_related('killhouse_user')
aggregate_kill_house_request = kill_house_request.aggregate(
total_id=Count('id'),
total_accepted_real_quantity=Sum('accepted_real_quantity'),
total_accepted_real_weight=Sum('accepted_real_weight'),
total_quantity_has_quarantine=Sum('accepted_real_quantity', filter=Q(quarantine_quantity__gt=0)),
total_count_has_quarantine=Count('id', filter=Q(quarantine_quantity__gt=0)),
total_quarantine_quantity=Sum('quarantine_quantity', filter=Q(quarantine_quantity__gt=0)),
total_id_hasnt_code=Count('id', filter=Q(clearance_code__isnull=True)),
total_quantity_hasnt_code=Sum('accepted_real_quantity', filter=Q(clearance_code__isnull=True)),
total_weight_hasnt_code=Sum('accepted_real_weight', filter=Q(clearance_code__isnull=True)),
total_id_hasnt_warehouse=Count('id', filter=Q(ware_house_confirmation=False)),
total_quantity_hasnt_warehouse=Sum('accepted_real_quantity', filter=Q(ware_house_confirmation=False)),
total_weight_hasnt_warehouse=Sum('accepted_real_weight', filter=Q(ware_house_confirmation=False)),
total_id_hasnt_assignment_state_archive=Count('id', filter=Q(assignment_state_archive='pending')),
total_quantity_hasnt_assignment_state_archive=Sum('accepted_real_quantity',
filter=Q(assignment_state_archive='pending')),
total_weight_hasnt_assignment_state_archive=Sum('accepted_real_weight',
filter=Q(assignment_state_archive='pending')),
total_id_hasnt_killing_age=Count('id', filter=Q(province_request__poultry_request__killing_age__gte=60)),
total_quantity_hasnt_killing_age=Sum('accepted_real_quantity',
filter=Q(province_request__poultry_request__killing_age__gte=60)),
total_weight_hasnt_killing_age=Sum('accepted_real_weight',
filter=Q(province_request__poultry_request__killing_age__gte=60)),
)
kill_house_req_stats = kill_house_request.values('killhouse_user__name').annotate(
total_quantity=Sum('accepted_real_quantity'),
transaction_count=Count('id')
).order_by('-total_quantity')
top_kill_house_req = kill_house_req_stats.first() if kill_house_req_stats else None
kill_house_name_req = "-"
total_quantity_top_inner = 0
if top_kill_house_req:
kill_house_name_req = top_kill_house_req['killhouse_user__name']
total_quantity_top_inner = top_kill_house_req['total_quantity']
poultry_req_stats = kill_house_request.values(
'province_request__poultry_request__hatching__poultry__unit_name',
'province_request__poultry_request__hatching__poultry__user__city__name') \
.annotate(total_quantity=Sum('accepted_real_quantity'),
).order_by('-total_quantity')
top_poultry_req_stats = poultry_req_stats.first() if poultry_req_stats else None
top_poultry_req_stats_total_quantity = 0
poultry_req_name_req = "-"
poultry_city_req_name_req = "-"
if top_poultry_req_stats:
poultry_req_name_req = top_poultry_req_stats['province_request__poultry_request__hatching__poultry__unit_name']
poultry_city_req_name_req = top_poultry_req_stats[
'province_request__poultry_request__hatching__poultry__user__city__name']
top_poultry_req_stats_total_quantity = to_locale_str(top_poultry_req_stats['total_quantity'] or 0)
poultry_hatching_gt_60 = poultry_hatching.filter(chicken_age__gt=60)
poultry_hatching_has_killed = PoultryRequest.objects.filter(state_process__in=('pending', 'accepted'),
province_state__in=('pending', 'accepted'),
trash=False, out=False, send_date__date__gte=date1,
send_date__date__lte=date2)
max_age_poultry = poultry_hatching_has_killed.order_by('-killing_age').first()
min_age_poultry = poultry_hatching_has_killed.order_by('killing_age').first()
aggregate_poultry_hatching_gt_60 = poultry_hatching_gt_60.aggregate(
total_quantity=Sum('quantity'),
left_over=Sum('left_over'),
)
aggregate_hatching = poultry_hatching.aggregate(
total_quantity=Sum('quantity'),
total_losses_vet=Sum('losses'),
total_losses_union=Sum('direct_losses'),
total_losses=Sum('total_losses'),
killed_quantity=Sum('killed_quantity'),
total_killed_weight=Sum('total_killed_weight'),
left_over=Sum('left_over'),
total_killing_ave_age=Avg('poultry__killing_ave_age')
)
top_total_killed_weight = poultry_hatching.values('id').annotate(
total_killed_weight=Sum('total_killed_weight'),
).order_by('-total_killed_weight')
top_total_killed_weight_first = top_total_killed_weight.first() if top_total_killed_weight else None
free_bars = KillHouseFreeBarInformation.objects.filter(date__date__gte=date1,
date__date__lte=date2,
trash=False, buy_type='live').select_related('kill_house')
kill_house_stats = free_bars.values('kill_house__name').annotate(
total_quantity=Sum('quantity'),
total_live_weight=Sum('live_weight'),
transaction_count=Count('id')
).order_by('-total_quantity')
top_kill_house = kill_house_stats.first() if kill_house_stats else None
kill_house_name = "-"
total_quantity_top_out = 0
transaction_count = "-"
if top_kill_house:
kill_house_name = top_kill_house['kill_house__name']
transaction_count = to_locale_str(top_kill_house['transaction_count'] or 0)
total_quantity_top_out = to_locale_str(top_kill_house['total_quantity'] or 0)
#
out_poultry_req_stats = free_bars.values('poultry_name', 'province', 'city').annotate(
total_quantity=Sum('quantity'),
).order_by('-total_quantity')
top_out_poultry_req_stats = out_poultry_req_stats.first() if out_poultry_req_stats else None
out_top_poultry_req_stats_total_quantity = 0
out_poultry_req_name_req = "-"
out_poultry_city_req_name_req = "-"
out_poultry_province_req_name_req = "-"
if top_out_poultry_req_stats:
out_poultry_req_name_req = top_out_poultry_req_stats['poultry_name']
out_poultry_city_req_name_req = top_out_poultry_req_stats['city']
out_poultry_province_req_name_req = top_out_poultry_req_stats['province']
out_top_poultry_req_stats_total_quantity = to_locale_str(top_out_poultry_req_stats['total_quantity'] or 0)
#
aggregate_free_bars = free_bars.aggregate(
id=Count('id'),
quantity=Sum('quantity'),
live_weight=Sum('live_weight'),
)
max_kill_day = free_bars.values('date__date').annotate(
daily_quantity=Sum('quantity')
).order_by('-daily_quantity').first()
persian_date = '-'
daily_quantity = '-'
if max_kill_day:
persian_date = shamsi_date(max_kill_day['date__date'])
daily_quantity = to_locale_str(max_kill_day['daily_quantity'])
max_kill_day_req = kill_house_request.values('kill_request__recive_date__date').annotate(
daily_quantity=Sum('accepted_real_quantity')
).order_by('-daily_quantity').first()
persian_date_req = '-'
daily_quantity_req = '-'
if max_kill_day_req:
persian_date_req = shamsi_date(max_kill_day_req['kill_request__recive_date__date'])
daily_quantity_req = to_locale_str(max_kill_day_req['daily_quantity'])
kill_houses = KillHouse.objects.filter(trash=False, out_province=False).order_by('name')
kill_house_data = []
duc_kill_house_data = []
for kh in kill_houses:
in_province_data = kill_house_request.filter(
killhouse_user=kh
).aggregate(
load_count=Count('id'),
quantity=Sum('accepted_real_quantity'),
weight=Sum('accepted_real_weight')
)
out_province_data = free_bars.filter(
kill_house=kh
).aggregate(
load_count=Count('id'),
quantity=Sum('quantity'),
live_weight=Sum('live_weight'),
)
in_qty = in_province_data.get('quantity', 0) or 0
in_weight = in_province_data.get('weight', 0) or 0
out_qty = out_province_data.get('quantity', 0) or 0
out_weight = out_province_data.get('live_weight', 0) or 0
total_quantity = in_qty + out_qty
total_weight = in_weight + out_weight
in_loads = in_province_data.get('load_count', 0) or 0
out_loads = out_province_data.get('load_count', 0) or 0
total_loads = in_loads + out_loads
if in_qty > 0 or out_qty > 0 or in_loads > 0 or out_loads > 0:
kill_house_data.append({
'name': kh.name,
'load_count': to_locale_str(total_loads or 0),
'in_province_quantity': to_locale_str(in_qty or 0),
'in_province_wight': to_locale_str(in_weight or 0),
'out_province_quantity': to_locale_str(out_qty or 0),
'out_province_weight': to_locale_str(out_weight or 0),
'total_quantity': to_locale_str(total_quantity or 0),
'total_weight': to_locale_str(total_weight or 0),
})
bar_assigment_pending_count1 = kill_house_request.filter(assignment_state_archive='True') \
.exclude(bar_document_status__title__in=('تایید شده بدون کیفیت', 'تایید شد')).count()
tomorrow_of_date1 = date1 + datetime.timedelta(days=1)
tomorrow_of_date2 = date2 + datetime.timedelta(days=1)
steward_allocations = StewardAllocation.objects.filter(
trash=False,
date__date__gte=tomorrow_of_date1,
date__date__lte=tomorrow_of_date2,
kill_house__in=kill_houses
).values('kill_house_id').annotate(
total_quantity=Sum('real_weight_of_carcasses')
)
free_bars = KillHouseFreeSaleBarInformation.objects.filter(
trash=False,
date__date__gte=tomorrow_of_date1,
date__date__lte=tomorrow_of_date2,
kill_house__in=kill_houses
).values('kill_house_id').annotate(
total_quantity=Sum('weight_of_carcasses')
)
in_province_data = kill_house_request.filter(
killhouse_user__in=kill_houses
).values('killhouse_user_id').annotate(
total_quantity=Sum('accepted_real_weight')
)
in_warehouse_data = kill_house_request.filter(
killhouse_user__in=kill_houses,
ware_house_confirmation=True
).values('killhouse_user_id').annotate(
total_quantity=Sum('ware_house_accepted_real_weight')
)
products = RolesProducts.objects.filter(
trash=False,
kill_house__in=kill_houses
).values('kill_house_id', 'total_remain_weight')
steward_dict = {item['kill_house_id']: item['total_quantity'] for item in steward_allocations}
free_bar_dict = {item['kill_house_id']: item['total_quantity'] for item in free_bars}
in_province_dict = {item['killhouse_user_id']: item['total_quantity'] for item in in_province_data}
in_warehouse_dict = {item['killhouse_user_id']: item['total_quantity'] for item in in_warehouse_data}
product_dict = {item['kill_house_id']: item['total_remain_weight'] for item in products}
management_kill_house_data = []
for kh in kill_houses:
kh_id = kh.id
steward_qty = steward_dict.get(kh_id, 0) or 0
free_bar_qty = free_bar_dict.get(kh_id, 0) or 0
in_province_qty = in_province_dict.get(kh_id, 0) or 0
in_warehouse_qty = in_warehouse_dict.get(kh_id, 0) or 0
product_weight = product_dict.get(kh_id, 0) or 0
if any([in_province_qty, in_warehouse_qty, steward_qty, free_bar_qty]):
total = free_bar_qty + steward_qty
percent = round(total * 100 / in_province_qty, 1) if in_province_qty else 0
management_kill_house_data.append({
'name': kh.name,
'in_province_quantity': to_locale_str(in_province_qty),
'in_ware_house_quantity': to_locale_str(in_warehouse_qty),
'steward_allocation_quantity': to_locale_str(steward_qty),
'kill_house_free_bar_quantity': to_locale_str(free_bar_qty),
'all_quantity': to_locale_str(total),
'product': to_locale_str(product_weight),
'percent': percent
})
for kh in kill_houses:
kill_house_request1 = kill_house_request.filter(
killhouse_user=kh
)
bar_assigment_true_count = kill_house_request1.filter(assignment_state_archive='True')
bar_assigment_pending_count = kill_house_request1.filter(assignment_state_archive='pending').count()
bar_document_status_accepted = bar_assigment_true_count.filter(
bar_document_status__title__in=('تایید شده بدون کیفیت', 'تایید شد')).count()
bar_document_status_rejected = bar_assigment_true_count.exclude(
bar_document_status__title__in=('تایید شده بدون کیفیت', 'تایید شد')).count()
if bar_assigment_true_count.count() > 0 or bar_assigment_pending_count > 0:
duc_kill_house_data.append({
'name': kh.name,
'kill_house_request1_count': kill_house_request1.count(),
"bar_assigment_true_count": bar_assigment_true_count.count(),
"bar_assigment_pending_count": bar_assigment_pending_count,
"bar_document_status_accepted": bar_document_status_accepted,
"percent_bar_document_status_accepted": int((bar_document_status_accepted /
bar_assigment_true_count.count()) * 100) if
bar_assigment_true_count.count() > 0 else 0,
"bar_document_status_rejected": bar_document_status_rejected,
"percent_bar_document_status_rejected": int((bar_document_status_rejected /
bar_assigment_true_count.count()) * 100) if
bar_assigment_true_count.count() > 0 else 0,
})
if base_url_for_sms_report == 'ha':
province = 'همدان'
elif base_url_for_sms_report == 'ku':
province = 'کردستان'
elif base_url_for_sms_report == 'ma':
province = 'مرکزی'
elif base_url_for_sms_report == 'bu':
province = 'بوشهر'
else:
province = 'تست'
font_config = FontConfiguration()
different_bar = (aggregate_kill_house_request['total_quantity_has_quarantine'] or 0) \
- (aggregate_kill_house_request['total_quarantine_quantity'] or 0)
different_bar_percent = int(different_bar / (aggregate_kill_house_request['total_quarantine_quantity'] or 0) * 100) \
if (aggregate_kill_house_request['total_quarantine_quantity'] or 0) > 0 else 0
if different_bar < 0:
color_different_bar = '#FF0000'
else:
color_different_bar = None
html_content = render_to_string('management_all_poultry_and_warehouse.html', { # noqa
'number': 1234,
'province': province,
"date": shamsi_date(datetime.datetime.now().date(), in_value=True),
"date1": request.GET['date1'],
"date2": request.GET['date2'],
"from_date": shamsi_date(date1),
"to_date": shamsi_date(date2),
"poultry_count": len(poultry_hatching.values_list('poultry', flat=True).distinct()),
"chain_count": len(
poultry_hatching.filter(Q(UnionTypeName='زنجیره') |
Q(chain_company__isnull=False)).values_list('poultry', flat=True).distinct()),
"poultry_hatching_quantity": to_locale_str(aggregate_hatching['total_quantity'] or 0),
"poultry_hatching_losses_vet": to_locale_str(aggregate_hatching['total_losses_vet'] or 0),
"poultry_hatching_losses_union": to_locale_str(aggregate_hatching['total_losses_union'] or 0),
"poultry_hatching_total_losses": to_locale_str(aggregate_hatching['total_losses'] or 0),
"poultry_hatching_killed_quantity": to_locale_str(aggregate_hatching['killed_quantity'] or 0),
"poultry_hatching_total_killed_weight": to_locale_str(aggregate_hatching['total_killed_weight'] or 0),
"poultry_hatching_left_over": to_locale_str(aggregate_hatching['left_over'] or 0),
"poultry_hatching_gt_60": len(poultry_hatching_gt_60.values_list('poultry', flat=True).distinct()),
"poultry_hatching_gt_60_quantity": to_locale_str(aggregate_poultry_hatching_gt_60['total_quantity'] or 0),
"poultry_hatching_gt_60_left_over": to_locale_str(aggregate_poultry_hatching_gt_60['left_over'] or 0),
"max_age_poultry": max_age_poultry.killing_age or 0,
"max_age_poultry_name": max_age_poultry.hatching.poultry.unit_name or '-',
"max_age_poultry_city": max_age_poultry.hatching.poultry.user.city.name if max_age_poultry.hatching.poultry.user.city else '-',
"max_age_poultry_quantity": max_age_poultry.hatching.quantity or 0,
"max_age_poultry_killed_quantity": max_age_poultry.hatching.killed_quantity or 0,
"max_age_poultry_left_over": max_age_poultry.hatching.left_over or 0,
"min_age_poultry": min_age_poultry.killing_age or 0,
"min_age_poultry_name": min_age_poultry.hatching.poultry.unit_name or '-',
"min_age_poultry_city": min_age_poultry.hatching.poultry.user.city.name if min_age_poultry.hatching.poultry.user.city else '-',
"min_age_poultry_quantity": min_age_poultry.hatching.quantity or 0,
"min_age_poultry_killed_quantity": min_age_poultry.hatching.killed_quantity or 0,
"min_age_poultry_left_over": min_age_poultry.hatching.left_over or 0,
"kill_house_request_count": to_locale_str(aggregate_kill_house_request['total_id'] or 0),
"kill_house_request_quantity": to_locale_str(aggregate_kill_house_request['total_accepted_real_quantity'] or 0),
"kill_house_request_weight": to_locale_str(aggregate_kill_house_request['total_accepted_real_weight'] or 0),
"kill_house_request_average_weight": round(
aggregate_kill_house_request['total_accepted_real_weight'] / aggregate_kill_house_request[
'total_accepted_real_quantity'], 1)
if (aggregate_kill_house_request['total_accepted_real_quantity'] or 0) > 0 else 0,
"free_bars_count": to_locale_str(aggregate_free_bars['id'] or 0),
"free_bars_quantity": to_locale_str(aggregate_free_bars['quantity'] or 0),
"free_bars_live_weight": to_locale_str(aggregate_free_bars['live_weight'] or 0),
"kill_house_name": kill_house_name,
"transaction_count": transaction_count,
"persian_date": persian_date,
"daily_quantity": daily_quantity,
"persian_date_req": persian_date_req,
"daily_quantity_req": daily_quantity_req,
'kill_houses_data': kill_house_data,
'kill_house_name_req': kill_house_name_req,
'poultry_req_name_req': poultry_req_name_req,
'top_poultry_req_stats_total_quantity': top_poultry_req_stats_total_quantity,
'poultry_city_req_name_req': poultry_city_req_name_req,
'out_poultry_req_name_req': out_poultry_req_name_req,
'out_poultry_city_req_name_req': out_poultry_city_req_name_req,
'out_poultry_province_req_name_req': out_poultry_province_req_name_req,
'out_top_poultry_req_stats_total_quantity': out_top_poultry_req_stats_total_quantity,
'management_kill_house_data': management_kill_house_data,
'duc_kill_house_data': duc_kill_house_data,
'avg_losses': to_locale_str(int((aggregate_hatching['total_losses'] or 0) / poultry_hatching.count())),
'avg_total_killed_weight': round(
(aggregate_hatching['total_killed_weight'] or 0) / (aggregate_hatching['killed_quantity'] or 0), 1),
'total_killing_ave_age': int(aggregate_hatching['total_killing_ave_age'] or 0),
'top_total_killed_weight': to_locale_str(top_total_killed_weight_first['total_killed_weight'] or 0),
'total_quantity_top_inner': to_locale_str(total_quantity_top_inner),
'total_quantity_top_out': total_quantity_top_out,
'bar_assigment_pending_count1': to_locale_str(bar_assigment_pending_count1 or 0),
'base_url': base_url_for_sms_report,
"total_quarantine_quantity": to_locale_str(aggregate_kill_house_request['total_quarantine_quantity'] or 0),
"total_count_has_quarantine": to_locale_str(aggregate_kill_house_request['total_count_has_quarantine'] or 0),
"total_quantity_has_quarantine": to_locale_str(
aggregate_kill_house_request['total_quantity_has_quarantine'] or 0),
"different": to_locale_str(different_bar or 0),
"total_weight_hasnt_code": to_locale_str(aggregate_kill_house_request['total_weight_hasnt_code'] or 0),
"total_quantity_hasnt_code": to_locale_str(aggregate_kill_house_request['total_quantity_hasnt_code'] or 0),
"total_id_hasnt_code": to_locale_str(aggregate_kill_house_request['total_id_hasnt_code'] or 0),
"total_weight_hasnt_warehouse": to_locale_str(
aggregate_kill_house_request['total_weight_hasnt_warehouse'] or 0),
"total_quantity_hasnt_warehouse": to_locale_str(
aggregate_kill_house_request['total_quantity_hasnt_warehouse'] or 0),
"total_id_hasnt_warehouse": to_locale_str(aggregate_kill_house_request['total_id_hasnt_warehouse'] or 0),
"total_weight_hasnt_assignment_state_archive": to_locale_str(
aggregate_kill_house_request['total_weight_hasnt_assignment_state_archive'] or 0),
"total_quantity_hasnt_assignment_state_archive": to_locale_str(
aggregate_kill_house_request['total_quantity_hasnt_assignment_state_archive'] or 0),
"total_id_hasnt_assignment_state_archive": to_locale_str(
aggregate_kill_house_request['total_id_hasnt_assignment_state_archive'] or 0),
"total_weight_hasnt_killing_age": to_locale_str(
aggregate_kill_house_request['total_weight_hasnt_killing_age'] or 0),
"total_quantity_hasnt_killing_age": to_locale_str(
aggregate_kill_house_request['total_quantity_hasnt_killing_age'] or 0),
"total_id_hasnt_killing_age": to_locale_str(aggregate_kill_house_request['total_id_hasnt_killing_age'] or 0),
'color_different_bar': color_different_bar,
'different_bar_percent': different_bar_percent,
'tomorrow_of_date1': shamsi_date(tomorrow_of_date1),
'tomorrow_of_date2': shamsi_date(tomorrow_of_date2),
})
html = HTML(string=html_content, base_url=request.build_absolute_uri()) # noqa
css = CSS(string='''
''', font_config=font_config)
pdf_file = io.BytesIO()
html.write_pdf(pdf_file, stylesheets=[css], font_config=font_config)
pdf_file.seek(0)
response = HttpResponse(pdf_file, content_type='application/pdf')
filename = 'عملکرد کشتار زنجیره.pdf'
encoded_filename = quote(filename) # کدگذاری نام فایل برای URL
response['Content-Disposition'] = f'attachment; filename*=UTF-8\'\'{encoded_filename}'
return response
def summary_report_pdf(request):
if base_url_for_sms_report == 'ha':
province = 'همدان'
elif base_url_for_sms_report == 'ku':
province = 'کردستان'
elif base_url_for_sms_report == 'ma':
province = 'مرکزی'
elif base_url_for_sms_report == 'bu':
province = 'بوشهر'
else:
province = 'تست'
date1 = datetime.datetime.strptime(str(request.GET['date1']), '%Y-%m-%d').date()
date2 = datetime.datetime.strptime(str(request.GET['date2']), '%Y-%m-%d').date()
poultry_hatching = PoultryHatching.objects.filter(Q(date__date__gte=date1, date__date__lte=date2) |
Q(date__date__lte=date1,
archive_date__isnull=True) | Q(date__date__lte=date1,
archive_date__gte=date1,
archive_date__isnull=False),
trash=False).select_related('poultry', 'poultry__user__city')
kill_house_request = KillHouseRequest.objects.filter(
trash=False,
kill_request__recive_date__date__gte=date1,
kill_request__recive_date__date__lte=date2,
temporary_trash=False,
temporary_deleted=False
).select_related('killhouse_user')
aggregate_kill_house_request = kill_house_request.aggregate(
id=Count('id'),
accepted_real_quantity=Sum('accepted_real_quantity'),
accepted_real_weight=Sum('accepted_real_weight'),
)
kill_house_req_stats = kill_house_request.values('killhouse_user__name').annotate(
total_quantity=Sum('accepted_real_quantity'),
transaction_count=Count('id')
).order_by('-total_quantity')
top_kill_house_req = kill_house_req_stats.first() if kill_house_req_stats else None
kill_house_name_req = "-"
transaction_count_req = 0
total_quantity_top_inner = 0
if top_kill_house_req:
kill_house_name_req = top_kill_house_req['killhouse_user__name']
total_quantity_top_inner = top_kill_house_req['total_quantity']
transaction_count_req = top_kill_house_req['transaction_count']
# max_kill_day_req = kill_house_request.values('kill_request__recive_date__date').annotate(
# daily_quantity=Sum('quantity')
# ).order_by('-daily_quantity').first()
# persian_date_req = '-'
# daily_quantity_req = '-'
# if max_kill_day_req:
# persian_date = shamsi_date(max_kill_day_req['date__date'])
# daily_quantity = to_locale_str(max_kill_day_req['daily_quantity'])
poultry_req_stats = kill_house_request.values(
'province_request__poultry_request__hatching__poultry__unit_name',
'province_request__poultry_request__hatching__poultry__user__city__name') \
.annotate(total_quantity=Sum('accepted_real_quantity'),
).order_by('-total_quantity')
top_poultry_req_stats = poultry_req_stats.first() if poultry_req_stats else None
top_poultry_req_stats_total_quantity = 0
poultry_req_name_req = "-"
poultry_city_req_name_req = "-"
if top_poultry_req_stats:
poultry_req_name_req = top_poultry_req_stats['province_request__poultry_request__hatching__poultry__unit_name']
poultry_city_req_name_req = top_poultry_req_stats[
'province_request__poultry_request__hatching__poultry__user__city__name']
top_poultry_req_stats_total_quantity = to_locale_str(top_poultry_req_stats['total_quantity'] or 0)
poultry_hatching_gt_60 = poultry_hatching.filter(chicken_age__gt=60)
poultry_hatching_has_killed = poultry_hatching.filter(total_killed_weight__gt=0)
max_age_poultry = poultry_hatching_has_killed.order_by('-chicken_age').first()
min_age_poultry = poultry_hatching_has_killed.order_by('chicken_age').first()
aggregate_poultry_hatching_gt_60 = poultry_hatching_gt_60.aggregate(
total_quantity=Sum('quantity'),
left_over=Sum('left_over'),
)
aggregate_hatching = poultry_hatching.aggregate(
total_quantity=Sum('quantity'),
total_losses_vet=Sum('losses'),
total_losses_union=Sum('direct_losses'),
total_losses=Sum('total_losses'),
killed_quantity=Sum('killed_quantity'),
total_killed_weight=Sum('total_killed_weight'),
left_over=Sum('left_over'),
total_killing_ave_age=Avg('poultry__killing_ave_age')
)
top_total_killed_weight = poultry_hatching.values('id').annotate(
total_killed_weight=Sum('total_killed_weight'),
).order_by('-total_killed_weight')
top_total_killed_weight_first = top_total_killed_weight.first() if top_total_killed_weight else None
free_bars = KillHouseFreeBarInformation.objects.filter(date__date__gte=date1,
date__date__lte=date2,
trash=False).select_related('kill_house')
kill_house_stats = free_bars.values('kill_house__name').annotate(
total_quantity=Sum('quantity'),
total_live_weight=Sum('live_weight'),
transaction_count=Count('id')
).order_by('-total_quantity')
top_kill_house = kill_house_stats.first() if kill_house_stats else None
kill_house_name = "-"
total_quantity_top_out = 0
transaction_count = "-"
if top_kill_house:
kill_house_name = top_kill_house['kill_house__name']
transaction_count = to_locale_str(top_kill_house['transaction_count'] or 0)
total_quantity_top_out = to_locale_str(top_kill_house['total_quantity'] or 0)
#
out_poultry_req_stats = free_bars.values('poultry_name', 'province', 'city').annotate(
total_quantity=Sum('quantity'),
).order_by('-total_quantity')
top_out_poultry_req_stats = out_poultry_req_stats.first() if out_poultry_req_stats else None
out_top_poultry_req_stats_total_quantity = 0
out_poultry_req_name_req = "-"
out_poultry_city_req_name_req = "-"
out_poultry_province_req_name_req = "-"
if top_out_poultry_req_stats:
out_poultry_req_name_req = top_out_poultry_req_stats['poultry_name']
out_poultry_city_req_name_req = top_out_poultry_req_stats['city']
out_poultry_province_req_name_req = top_out_poultry_req_stats['province']
out_top_poultry_req_stats_total_quantity = to_locale_str(top_out_poultry_req_stats['total_quantity'] or 0)
#
aggregate_free_bars = free_bars.aggregate(
id=Count('id'),
quantity=Sum('quantity'),
live_weight=Sum('live_weight'),
)
max_kill_day = free_bars.values('date__date').annotate(
daily_quantity=Sum('quantity')
).order_by('-daily_quantity').first()
persian_date = '-'
daily_quantity = '-'
if max_kill_day:
persian_date = shamsi_date(max_kill_day['date__date'])
daily_quantity = to_locale_str(max_kill_day['daily_quantity'])
kill_houses = KillHouse.objects.filter(trash=False, out_province=False).order_by('name')
kill_house_data = []
duc_kill_house_data = []
for kh in kill_houses:
in_province_data = kill_house_request.filter(
killhouse_user=kh
).aggregate(
load_count=Count('id'),
quantity=Sum('accepted_real_quantity'),
weight=Sum('accepted_real_weight')
)
out_province_data = free_bars.filter(
kill_house=kh
).aggregate(
load_count=Count('id'),
quantity=Sum('quantity'),
live_weight=Sum('live_weight'),
)
in_qty = in_province_data.get('quantity', 0) or 0
out_qty = out_province_data.get('quantity', 0) or 0
total_quantity = in_qty + out_qty
in_loads = in_province_data.get('load_count', 0) or 0
out_loads = out_province_data.get('load_count', 0) or 0
total_loads = in_loads + out_loads
if in_qty > 0 or out_qty > 0 or in_loads > 0 or out_loads > 0:
kill_house_data.append({
'name': kh.name,
'load_count': to_locale_str(total_loads or 0),
'in_province_quantity': to_locale_str(in_qty or 0),
'out_province_quantity': to_locale_str(out_qty or 0),
'total_quantity': to_locale_str(total_quantity or 0),
})
bar_assigment_pending_count1 = kill_house_request.filter(assignment_state_archive='True') \
.exclude(bar_document_status__title__in=('تایید شده بدون کیفیت', 'تایید شد')).count()
steward_allocations = StewardAllocation.objects.filter(
trash=False,
date__date__gte=date1,
date__date__lte=date2,
kill_house__in=kill_houses
).values('kill_house_id').annotate(
total_quantity=Sum('real_weight_of_carcasses')
)
steward_allocations_stats = steward_allocations.values('kill_house__name').annotate(
total_quantity=Sum('real_weight_of_carcasses'),
).order_by('-total_quantity')
top_steward_allocations_stats = steward_allocations_stats.first() if steward_allocations_stats else None
out_kill_house_top = "-"
out_weight_top = 0
if top_steward_allocations_stats:
out_kill_house_top = top_steward_allocations_stats['kill_house__name']
out_weight_top = to_locale_str(top_steward_allocations_stats['total_quantity'] or 0)
free_bars = KillHouseFreeSaleBarInformation.objects.filter(
trash=False,
date__date__gte=date1,
date__date__lte=date2,
kill_house__in=kill_houses
).values('kill_house_id', 'kill_house__name').annotate(
total_quantity=Sum('weight_of_carcasses')
).order_by('-total_quantity')
top_free_bars_stats = free_bars.first() if free_bars else None
free_bars_kill_house_top = "-"
free_bars_weight_top = 0
if top_free_bars_stats:
free_bars_kill_house_top = top_free_bars_stats['kill_house__name']
free_bars_weight_top = to_locale_str(top_free_bars_stats['total_quantity'] or 0)
in_province_data = kill_house_request.filter(
killhouse_user__in=kill_houses
).values('killhouse_user_id').annotate(
total_quantity=Sum('accepted_real_weight')
)
in_warehouse_data = kill_house_request.filter(
killhouse_user__in=kill_houses,
ware_house_confirmation=True
).values('killhouse_user_id').annotate(
total_quantity=Sum('ware_house_accepted_real_weight')
)
products = RolesProducts.objects.filter(
trash=False,
kill_house__in=kill_houses
).values('kill_house_id', 'total_remain_weight')
steward_dict = {item['kill_house_id']: item['total_quantity'] for item in steward_allocations}
free_bar_dict = {item['kill_house_id']: item['total_quantity'] for item in free_bars}
in_province_dict = {item['killhouse_user_id']: item['total_quantity'] for item in in_province_data}
in_warehouse_dict = {item['killhouse_user_id']: item['total_quantity'] for item in in_warehouse_data}
product_dict = {item['kill_house_id']: item['total_remain_weight'] for item in products}
bar_assigment_true_count1 = kill_house_request.filter(assignment_state_archive='True')
bar_document_status_rejected1 = bar_assigment_true_count1.exclude(
bar_document_status__title__in=('تایید شده بدون کیفیت', 'تایید شد')).count()
percent_bar_document_status_rejected_all = int((bar_document_status_rejected1 /
bar_assigment_true_count1.count()) * 100) if \
bar_assigment_true_count1.count() > 0 else 0
management_kill_house_data = []
for kh in kill_houses:
kh_id = kh.id
steward_qty = steward_dict.get(kh_id, 0) or 0
free_bar_qty = free_bar_dict.get(kh_id, 0) or 0
in_province_qty = in_province_dict.get(kh_id, 0) or 0
in_warehouse_qty = in_warehouse_dict.get(kh_id, 0) or 0
product_weight = product_dict.get(kh_id, 0) or 0
if any([in_province_qty, in_warehouse_qty, steward_qty, free_bar_qty]):
total = free_bar_qty + steward_qty
percent = round(total * 100 / in_province_qty, 1) if in_province_qty else 0
management_kill_house_data.append({
'name': kh.name,
'in_province_quantity': to_locale_str(in_province_qty),
'in_ware_house_quantity': to_locale_str(in_warehouse_qty),
'steward_allocation_quantity': to_locale_str(steward_qty),
'kill_house_free_bar_quantity': to_locale_str(free_bar_qty),
'all_quantity': to_locale_str(total),
'product': to_locale_str(product_weight),
'percent': percent
})
for kh in kill_houses:
kill_house_request1 = kill_house_request.filter(
killhouse_user=kh
)
bar_assigment_true_count = kill_house_request1.filter(assignment_state_archive='True')
bar_assigment_pending_count = kill_house_request1.filter(assignment_state_archive='pending').count()
bar_document_status_accepted = bar_assigment_true_count.filter(
bar_document_status__title__in=('تایید شده بدون کیفیت', 'تایید شد')).count()
bar_document_status_rejected = bar_assigment_true_count.exclude(
bar_document_status__title__in=('تایید شده بدون کیفیت', 'تایید شد')).count()
if bar_assigment_true_count.count() > 0 or bar_assigment_pending_count > 0:
duc_kill_house_data.append({
'name': kh.name,
'kill_house_request1_count': kill_house_request1.count(),
"bar_assigment_true_count": bar_assigment_true_count.count(),
"bar_assigment_pending_count": bar_assigment_pending_count,
"bar_document_status_accepted": bar_document_status_accepted,
"percent_bar_document_status_accepted": int((bar_document_status_accepted /
bar_assigment_true_count.count()) * 100) if
bar_assigment_true_count.count() > 0 else 0,
"bar_document_status_rejected": bar_document_status_rejected,
"percent_bar_document_status_rejected": int((bar_document_status_rejected /
bar_assigment_true_count.count()) * 100) if
bar_assigment_true_count.count() > 0 else 0,
})
font_config = FontConfiguration()
html_content = render_to_string('summary_report.html', { # noqa
'number': 1234,
'province': province,
"date": shamsi_date(datetime.datetime.now().date(), in_value=True),
"date1": request.GET['date1'],
"date2": request.GET['date2'],
"from_date": shamsi_date(date1),
"to_date": shamsi_date(date2),
"out_kill_house_top": out_kill_house_top,
"out_weight_top": out_weight_top,
"free_bars_weight_top": free_bars_weight_top,
"free_bars_kill_house_top": free_bars_kill_house_top,
"steward_sum_weight_sale": to_locale_str(sum(steward_dict.values())),
"free_bar_sum_weight_sale": to_locale_str(sum(free_bar_dict.values())),
"poultry_count": len(poultry_hatching.values_list('poultry', flat=True).distinct()),
"chain_count": len(
poultry_hatching.filter(Q(UnionTypeName='زنجیره') |
Q(chain_company__isnull=False)).values_list('poultry', flat=True).distinct()),
"poultry_hatching_quantity": to_locale_str(aggregate_hatching['total_quantity'] or 0),
"poultry_hatching_total_losses": to_locale_str(aggregate_hatching['total_losses'] or 0),
"poultry_hatching_killed_quantity": to_locale_str(aggregate_hatching['killed_quantity'] or 0),
"poultry_hatching_left_over": to_locale_str(aggregate_hatching['left_over'] or 0),
"poultry_hatching_gt_60": len(poultry_hatching_gt_60.values_list('poultry', flat=True).distinct()),
"poultry_hatching_gt_60_quantity": to_locale_str(aggregate_poultry_hatching_gt_60['total_quantity'] or 0),
"poultry_hatching_gt_60_left_over": round(((aggregate_poultry_hatching_gt_60['left_over'] or 0) /
(aggregate_poultry_hatching_gt_60['total_quantity'] or 0) * 100,
1) if
(aggregate_poultry_hatching_gt_60['total_quantity'] or 0) < 0 else
0),
"max_age_poultry": to_locale_str(max_age_poultry.chicken_age or 0),
"max_age_poultry_name": max_age_poultry.poultry.unit_name or '-',
"max_age_poultry_city": max_age_poultry.poultry.user.city.name if max_age_poultry.poultry.user.city else '-',
"min_age_poultry": to_locale_str(min_age_poultry.chicken_age or 0),
"min_age_poultry_name": min_age_poultry.poultry.unit_name or '-',
"min_age_poultry_city": min_age_poultry.poultry.user.city.name if min_age_poultry.poultry.user.city else '-',
"kill_house_request_count": to_locale_str(aggregate_kill_house_request['id'] or 0),
"kill_house_request_quantity": to_locale_str(aggregate_kill_house_request['accepted_real_quantity'] or 0),
"kill_house_request_weight": to_locale_str(aggregate_kill_house_request['accepted_real_weight'] or 0),
"kill_house_request_average_weight": round(
aggregate_kill_house_request['accepted_real_weight'] / aggregate_kill_house_request[
'accepted_real_quantity'], 1)
if (aggregate_kill_house_request['accepted_real_quantity'] or 0) > 0 else 0,
"free_bars_count": to_locale_str(aggregate_free_bars['id'] or 0),
"free_bars_quantity": to_locale_str(aggregate_free_bars['quantity'] or 0),
"free_bars_live_weight": to_locale_str(aggregate_free_bars['live_weight'] or 0),
"kill_house_name": kill_house_name,
"transaction_count": transaction_count,
"persian_date": persian_date,
"transaction_count_req": transaction_count_req,
"daily_quantity": daily_quantity,
'kill_houses_data': kill_house_data,
'kill_house_name_req': kill_house_name_req,
'poultry_req_name_req': poultry_req_name_req,
'top_poultry_req_stats_total_quantity': top_poultry_req_stats_total_quantity,
'poultry_city_req_name_req': poultry_city_req_name_req,
'out_poultry_req_name_req': out_poultry_req_name_req,
'out_poultry_city_req_name_req': out_poultry_city_req_name_req,
'out_poultry_province_req_name_req': out_poultry_province_req_name_req,
'out_top_poultry_req_stats_total_quantity': out_top_poultry_req_stats_total_quantity,
'management_kill_house_data': management_kill_house_data,
'duc_kill_house_data': duc_kill_house_data,
'avg_losses': to_locale_str(int((aggregate_hatching['total_losses'] or 0) / poultry_hatching.count())),
'avg_total_killed_weight': round(
(aggregate_hatching['total_killed_weight'] or 0) / (aggregate_hatching['killed_quantity'] or 0), 1),
'total_killing_ave_age': int(aggregate_hatching['total_killing_ave_age'] or 0),
'top_total_killed_weight': to_locale_str(top_total_killed_weight_first['total_killed_weight'] or 0),
'total_quantity_top_inner': to_locale_str(total_quantity_top_inner),
'total_quantity_top_out': total_quantity_top_out,
'bar_assigment_pending_count1': to_locale_str(bar_assigment_pending_count1 or 0),
'base_url': base_url_for_sms_report,
'percent_bar_document_status_rejected_all': percent_bar_document_status_rejected_all,
})
html = HTML(string=html_content, base_url=request.build_absolute_uri()) # noqa
css = CSS(string='''
''', font_config=font_config)
pdf_file = io.BytesIO()
html.write_pdf(pdf_file, stylesheets=[css], font_config=font_config)
pdf_file.seek(0)
response = HttpResponse(pdf_file, content_type='application/pdf')
filename = 'عملکرد کشتار زنجیره.pdf'
encoded_filename = quote(filename) # کدگذاری نام فایل برای URL
response['Content-Disposition'] = f'attachment; filename*=UTF-8\'\'{encoded_filename}'
return response
def hatching_detail_pdf(request):
if base_url_for_sms_report == 'ha':
province = 'همدان'
elif base_url_for_sms_report == 'ku':
province = 'کردستان'
elif base_url_for_sms_report == 'ma':
province = 'مرکزی'
elif base_url_for_sms_report == 'bu':
province = 'بوشهر'
else:
province = 'تست'
hatching = PoultryHatching.objects.filter(
trash=False,
key=request.GET['key']
).select_related('poultry').first()
ser_data = PoultryHatchingForDetailsSerializer(hatching).data
kill_requests = KillHouseRequest.objects.filter(
trash=False,
province_request__poultry_request__hatching=hatching,
ware_house_confirmation=True
).select_related(
'killhouse_user',
'killer',
'province_request',
'province_request__poultry_request',
'kill_request'
).order_by('-create_date')
ser_data_kill_request = KillHouseRequestForHatchingDetailSerializer(kill_requests, many=True).data
poultry_requests = PoultryRequest.objects.filter(hatching=hatching, trash=False,
state_process__in=('pending', 'accepted'),
province_state__in=('pending', 'accepted'), out=True,
out_province_request_cancel=False,
temporary_trash=False,
temporary_deleted=False)
ser_data_poultry_request = PoultryRequestForHatchingDetailSerializer(poultry_requests, many=True).data
chain_allocation = ChainAllocation.objects.filter(trash=False, state='accepted', poultry_hatching=hatching)
ser_data_chain_allocation = ChainAllocationForHatchingDetailSerializer(chain_allocation, many=True).data
evacuation_reports = []
if hatching:
detail_qs = hatching.evacuation_details.filter(trash=False).order_by('-ReportDate', '-create_date')
evacuation_reports = EvacuationHatchingDetailSerializer(detail_qs, many=True).data
poultry_hatching_licence_number = hatching.licence_number
response = requests.post(
f'https://rsibackend.rasadyar.com/app/send_different_bar_with_licence_number/?'
f'licence_number={poultry_hatching_licence_number}'
f'&date1={None}&date2={None}',
headers={'Content-Type': 'application/json'}
)
kill_requests_non_receipt = KillHouseRequest.objects.filter(
trash=False,
province_request__poultry_request__hatching=hatching,
non_receipt=True, main_non_receipt=True
).select_related(
'killhouse_user',
'killer',
'province_request',
'province_request__poultry_request',
'kill_request'
).order_by('-create_date')
ser_data_non_receipt_kill_request = KillHouseRequestForHatchingDetailSerializer(kill_requests_non_receipt,
many=True).data
bar_requests = BarDifferenceRequest.objects.filter(trash=False,
state='accepted', hatching=hatching).order_by('id')
bar_request_serilizer = BarDifferenceRequestSerializer(bar_requests, many=True).data
hatching_increase = HatchingIncreaseRequest.objects.filter(trash=False, hatching=hatching).order_by('-date')
hatching_increase_serilizer = HatchingIncreaseRequestSerializer(hatching_increase, many=True).data
filters = {
'archive_wage': False,
'state__in': ('pending', 'accepted'),
'first_car_allocated_quantity': 0
}
return_province_kill_requests = ProvinceKillRequest.objects.filter(
Q(trash=False, return_to_province=True) | Q(trash=True, return_trash=True), **filters,
province_request__poultry_request__hatching=hatching).order_by('id')
return_province_kill_requests_serializer = ReturnProvinceKillRequestSerializer(return_province_kill_requests,
many=True).data
kill_house_requests_return = KillHouseRequest.objects.filter(
Q(non_receipt=True, main_non_receipt=True, non_receipt_state='accepted') | Q(trash=True, return_trash=True),
province_request__poultry_request__hatching=hatching)
kill_house_requests_return_serializer = KillHouseRequestForBarManagementSerializer(kill_house_requests_return,
many=True).data
font_config = FontConfiguration()
html_content = render_to_string('poultry_datail.html', { # noqa
'province': province,
"shamsi_date": shamsi_date(datetime.datetime.now().date(), in_value=True),
"hatching_date": shamsi_date(hatching.date, in_value=True),
"create_date_hatching": shamsi_date(hatching.create_date, in_value=True),
"predicate_date_hatching": shamsi_date(hatching.predicate_date,
in_value=True) if hatching.predicate_date else '-',
**ser_data,
"bars": ser_data_kill_request[:20] if len(ser_data_kill_request) > 20 else ser_data_kill_request,
"bars2": ser_data_kill_request[20:] if len(ser_data_kill_request) > 20 else None,
'outBars': ser_data_poultry_request[:20] if len(ser_data_poultry_request) > 20 else ser_data_poultry_request,
'outBars2': ser_data_poultry_request[20:] if len(ser_data_poultry_request) > 20 else None,
'chainAllocation': ser_data_chain_allocation[20:] if len(
ser_data_chain_allocation) > 20 else ser_data_chain_allocation,
'chainAllocation2': ser_data_chain_allocation[20:] if len(ser_data_chain_allocation) > 20 else None,
'percent_rasadyar1': round(
((ser_data['killed_quantity'] + ser_data['total_losses']) * 100) / ser_data['quantity'])
if ser_data['quantity'] > 0 else 0,
'active_kill1': 'دارد' if ser_data['active_kill']['active_kill'] else 'ندارد',
"differentBars": response.json()[:20],
"differentBars2": response.json()[20:],
"nonReceipt": ser_data_non_receipt_kill_request,
"returnProvinceRequest": return_province_kill_requests_serializer,
"returnKillHouseRequest": kill_house_requests_return_serializer,
"killingDifference": bar_request_serilizer,
"hatchingIncrease": hatching_increase_serilizer,
"evacuation_reports": evacuation_reports,
})
html = HTML(string=html_content, base_url=request.build_absolute_uri()) # noqa
css = CSS(string='''
''', font_config=font_config)
pdf_file = io.BytesIO()
html.write_pdf(pdf_file, stylesheets=[css], font_config=font_config)
pdf_file.seek(0)
response = HttpResponse(pdf_file, content_type='application/pdf')
filename = 'عملکرد کشتار زنجیره.pdf'
encoded_filename = quote(filename) # کدگذاری نام فایل برای URL
response['Content-Disposition'] = f'attachment; filename*=UTF-8\'\'{encoded_filename}'
return response
def poultry_science_report_pdf(request):
"""
تولید PDF گزارش بازرسی مرغداری
ساختار JSON بر اساس کد React:
- generalConditionHall, casualties, technicalOfficer
- inputStatus, infrastructureEnergy, facilities, hr
- inspectionNotes, inspectionStatus
"""
font_config = FontConfiguration()
report = PoultryScienceReport.objects.filter(
trash=False,
key=request.GET['key']
).select_related(
'hatching',
'hatching__poultry',
'hatching__poultry__user',
'hatching__poultry__user__city',
'hatching__poultry__address',
'poultry_science',
'poultry_science__user',
'user'
).first()
if not report:
return HttpResponse("گزارش یافت نشد", status=404)
report_data = report.report_information or {}
hatching = report.hatching
poultry = hatching.poultry if hatching else None
# استخراج بخش‌های مختلف JSON (با snake_case)
general_condition = report_data.get('general_condition_hall', {}) or {}
casualties = report_data.get('casualties', {}) or {}
technical_officer = report_data.get('technical_officer', {}) or {}
input_status_data = report_data.get('input_status', {}) or {}
infrastructure_energy = report_data.get('infrastructure_energy', {}) or {}
facilities = report_data.get('facilities', {}) or {}
hr = report_data.get('hr', {}) or {}
# تابع کمکی برای مقادیر
def safe_get(data, key, default='---'):
if not isinstance(data, dict):
return default
value = data.get(key)
return value if value not in [None, '', 'null'] else default
def format_number(value):
if value is None:
return '---'
try:
return f"{int(value):,}"
except (ValueError, TypeError):
return str(value) if value else '---'
# اطلاعات سربرگ
inspection_date = shamsi_date(report.date, in_value=True) if report.date else '---'
report_id = report.report_id or '---'
unit_name = poultry.unit_name if poultry else '---'
breeding_unique_id = poultry.breeding_unique_id if poultry else '---'
licence_number = hatching.licence_number if hatching else '---'
city = poultry.user.city.name if poultry and poultry.user and poultry.user.city else '---'
hatching_date = shamsi_date(hatching.date, in_value=True) if hatching and hatching.date else '---'
initial_quantity = format_number(hatching.quantity) if hatching else '---'
# وضعیت بازرسی
status_map = {'pending': 'در انتظار', 'accepted': 'تایید شده', 'rejected': 'رد شده'}
inspection_status = status_map.get(report.state, report.state or 'در انتظار')
# === بخش اطلاعات (informationData) ===
health_permit = poultry.health_certificate_number if poultry and hasattr(poultry,
'health_certificate_number') else '---'
epidemiological_code = poultry.epidemiological_code if poultry and hasattr(poultry,
'epidemiological_code') else '---'
permit_validity = format_number(poultry.operating_licence_capacity) if poultry and hasattr(poultry,
'operating_licence_capacity') else '---'
tenant_status = hatching.InteractTypeName if hatching and hatching.InteractTypeName else (
'دارد' if (hatching and hasattr(hatching, 'has_tenant') and hatching.has_tenant) else 'ندارد')
owner_name = poultry.user.fullname if poultry and poultry.user else '---'
ownership_type = hatching.InteractTypeName if hatching else '---'
owner_national_code = (poultry.user.national_id if hasattr(poultry.user, 'national_id') and poultry.user.national_id
else (poultry.user.national_code if hasattr(poultry.user,
'national_code') else '---')) if poultry and poultry.user else '---'
province = poultry.address.province.name if poultry and poultry.address and hasattr(poultry.address,
'province') and poultry.address.province else '---'
coordinates = f"{report.lat}, {report.log}" if report.lat and report.log else (
f"{poultry.Lat}, {poultry.Long}" if poultry and hasattr(poultry, 'Lat') and poultry.Lat else '---')
owner_mobile = poultry.user.mobile if poultry and poultry.user else '---'
nominal_capacity = format_number(poultry.total_capacity) if poultry and hasattr(poultry,
'total_capacity') else '---'
vet_quantity = format_number(hatching.quantity) if hatching else '---'
self_declared_quantity = format_number(hatching.quantity) if hatching else '---'
chick_source = safe_get(casualties, 'source_of_hatching')
chicken_age = f"{hatching.chicken_age} روز" if hatching and hatching.chicken_age else '---'
breed_type = hatching.chicken_breed if hatching else '---'
# === بخش پایش سلامت (healthMonitoringData) ===
health_status = safe_get(general_condition, 'health_status')
ventilation_status = safe_get(general_condition, 'ventilation_status')
bedding_status = safe_get(general_condition, 'bed_condition')
temperature_humidity = f"{general_condition.get('temperature')} درجه" if general_condition.get(
'temperature') else '---'
water_quality = safe_get(general_condition, 'drinking_water_quality')
water_source = safe_get(general_condition, 'drinking_water_source')
normal_losses = format_number(casualties.get('normal_losses')) if casualties.get(
'normal_losses') is not None else '---'
abnormal_losses = format_number(casualties.get('abnormal_losses')) if casualties.get(
'abnormal_losses') is not None else '---'
abnormal_losses_reason = safe_get(casualties, 'cause_abnormal_losses')
disease_type = safe_get(casualties, 'type_disease')
sampling_done = 'بله' if casualties.get('sampling_done') else 'خیر'
sample_type = safe_get(casualties, 'type_sampling')
health_responsible = safe_get(technical_officer, 'technical_health_officer')
engineering_responsible = safe_get(technical_officer, 'technical_engineering_officer')
# === بخش زیرساخت (infrastructureData) ===
input_status = safe_get(input_status_data, 'input_status')
feed_type = safe_get(input_status_data, 'type_of_grain')
feed_quality = safe_get(input_status_data, 'grade_grain')
inventory_until_visit = safe_get(input_status_data, 'inventory_until_visit')
warehouse_inventory = safe_get(input_status_data, 'inventory_in_warehouse')
tracking_code = safe_get(input_status_data, 'tracking_code')
company_name = safe_get(input_status_data, 'company_name')
generator_type = safe_get(infrastructure_energy, 'generator_type')
generator_model = safe_get(infrastructure_energy, 'generator_model')
generator_count = safe_get(infrastructure_energy, 'generator_count')
fuel_type = safe_get(infrastructure_energy, 'fuel_type')
generator_capacity = format_number(infrastructure_energy.get('generator_capacity'))
emergency_fuel = format_number(infrastructure_energy.get('emergency_fuel_inventory'))
power_cut_history = 'بله' if infrastructure_energy.get('has_power_cut_history') else 'خیر'
power_cut_duration = f"{infrastructure_energy.get('power_cut_duration')} ساعت" if infrastructure_energy.get(
'power_cut_duration') else '---'
power_cut_hour = safe_get(infrastructure_energy, 'power_cut_hour')
generator_status = safe_get(infrastructure_energy, 'generator_performance')
additional_notes = safe_get(infrastructure_energy, 'additional_notes')
# نیروی انسانی
employee_count = safe_get(hr, 'number_employed')
local_employee_count = safe_get(hr, 'number_indigenous')
non_local_employee_count = safe_get(hr, 'number_non_indigenous')
worker_contract_status = safe_get(hr, 'contract_status')
health_training = 'بله' if hr.get('trained') else 'خیر'
# تسهیلات
active_facilities = 'بله' if facilities.get('has_facilities') else 'خیر'
facility_type = safe_get(facilities, 'type_of_facility')
facility_amount = format_number(facilities.get('amount'))
repayment_status = safe_get(facilities, 'repayment_status')
new_request = safe_get(facilities, 'request_facilities')
facility_date = shamsi_date(facilities.get('date')) if facilities.get('date') else '---'
# مستندات
hall_images = general_condition.get('images', []) or []
warehouse_images = input_status_data.get('images', []) or []
losses_images = casualties.get('images', []) or []
violation_images = hatching.violation_image if hatching and hasattr(hatching,
'violation_image') and hatching.violation_image else []
# توصیه‌ها
recommendations = report_data.get('inspection_notes', '---') or '---'
inspection_status_text = report_data.get('inspection_status', '---') or '---'
# احراز مسئول سالن (از vet_farm جوجه‌ریزی)
vet_farm = None
if hatching:
from panel.models import VetFarm
vet_farm = VetFarm.objects.filter(poultry=poultry, trash=False).first()
hall_responsible_present = 'بله' if (vet_farm and vet_farm.vet and vet_farm.vet.user) else 'خیر'
hall_responsible_name = vet_farm.vet.user.fullname if vet_farm and vet_farm.vet and vet_farm.vet.user else '---'
hall_responsible_phone = vet_farm.vet.user.mobile if vet_farm and vet_farm.vet and vet_farm.vet.user else '---'
html_content = render_to_string('poultry_science_report.html', {
# سربرگ
'inspection_date': inspection_date,
'report_id': report_id,
'unit_name': unit_name,
'breeding_unique_id': breeding_unique_id,
'licence_number': licence_number,
'city': city,
'hatching_date': hatching_date,
'initial_quantity': initial_quantity,
'inspection_status': inspection_status,
# اطلاعات واحد
'health_permit': health_permit,
'hatching_licence': licence_number,
'epidemiological_code': epidemiological_code,
'permit_validity': permit_validity,
'tenant_status': tenant_status,
'owner_name': owner_name,
'ownership_type': ownership_type,
'owner_national_code': owner_national_code,
'province': province,
'coordinates': coordinates,
'owner_mobile': owner_mobile,
'nominal_capacity': nominal_capacity,
'vet_quantity': vet_quantity,
'self_declared_quantity': self_declared_quantity,
'chick_source': chick_source,
'chicken_age': chicken_age,
'breed_type': breed_type,
# پایش سلامت
'health_status': health_status,
'ventilation_status': ventilation_status,
'bedding_status': bedding_status,
'temperature_humidity': temperature_humidity,
'water_quality': water_quality,
'water_source': water_source,
'normal_losses': normal_losses,
'abnormal_losses': abnormal_losses,
'abnormal_losses_reason': abnormal_losses_reason,
'disease_type': disease_type,
'sampling_done': sampling_done,
'sample_type': sample_type,
'health_responsible': health_responsible,
'engineering_responsible': engineering_responsible,
# زیرساخت
'input_status': input_status,
'feed_type': feed_type,
'feed_quality': feed_quality,
'inventory_until_visit': inventory_until_visit,
'warehouse_inventory': warehouse_inventory,
'tracking_code': tracking_code,
'company_name': company_name,
'generator_type': generator_type,
'generator_model': generator_model,
'generator_count': generator_count,
'fuel_type': fuel_type,
'generator_capacity': generator_capacity,
'emergency_fuel': emergency_fuel,
'power_cut_history': power_cut_history,
'power_cut_duration': power_cut_duration,
'power_cut_hour': power_cut_hour,
'generator_status': generator_status,
'additional_notes': additional_notes,
# نیروی انسانی
'employee_count': employee_count,
'local_employee_count': local_employee_count,
'non_local_employee_count': non_local_employee_count,
'worker_contract_status': worker_contract_status,
'health_training': health_training,
'active_facilities': active_facilities,
'facility_type': facility_type,
'facility_amount': facility_amount,
'repayment_status': repayment_status,
'new_request': new_request,
'facility_date': facility_date,
# مستندات
'hall_images': hall_images,
'warehouse_images': warehouse_images,
'losses_images': losses_images,
'violation_images': violation_images,
# توصیه‌ها و احراز
'recommendations': recommendations,
'inspection_status_text': inspection_status_text,
'hall_responsible_present': hall_responsible_present,
'hall_responsible_name': hall_responsible_name,
'hall_responsible_phone': hall_responsible_phone,
})
html = HTML(string=html_content, base_url=request.build_absolute_uri())
css = CSS(string='', font_config=font_config)
pdf_file = io.BytesIO()
html.write_pdf(pdf_file, stylesheets=[css], font_config=font_config)
pdf_file.seek(0)
response = HttpResponse(pdf_file, content_type='application/pdf')
filename = f'گزارش بازرسی {report_id}.pdf'
encoded_filename = quote(filename)
response['Content-Disposition'] = f'attachment; filename*=UTF-8\'\'{encoded_filename}'
return response
def kill_house_debt_report_pdf(request):
font_config = FontConfiguration()
kill_houses = KillHouse.objects.filter(
trash=False,
out_province=False
).select_related('kill_house_operator__user', 'system_address').order_by('name')
kill_house_data = []
production_date = (datetime.datetime.now() - datetime.timedelta(days=3)).date()
yesterday = (datetime.datetime.now() - datetime.timedelta(days=1)).date()
for kill_house in kill_houses:
ware_house_lock = False
if kill_house.ware_house_remaining_weight_limitation_status:
if kill_house.total_remain_warehouse_governmental_weight > kill_house.ware_house_remaining_weight_limitation:
ware_house_lock = True
if kill_house.ware_house_remaining_percent_limitation_status:
if not check_kill_house_remain_limitation_weight(kill_house):
ware_house_lock = True
if not ware_house_lock:
continue
kill_house_requests = KillHouseRequest.objects.filter(
input_warehouse=kill_house,
province_request__poultry_request__free_sale_in_province=False,
kill_request__recive_date__date=production_date,
ware_house_confirmation=True,
trash=False,
calculate_status=True,
warehouse=True
)
kill_house_allocations = StewardAllocation.objects.filter(
kill_house=kill_house,
trash=False,
calculate_status=True,
warehouse=True,
system_registration_code=True,
receiver_state__in=('pending', 'accepted'),
production_date__date=production_date,
quota='governmental'
)
kill_house_free_sale_bars = KillHouseFreeSaleBarInformation.objects.filter(
kill_house=kill_house,
quota='governmental',
production_date__date=production_date,
trash=False,
calculate_status=True,
warehouse=True
)
segmentations = PosSegmentation.objects.filter(
kill_house=kill_house,
production_date__date=production_date,
trash=False,
warehouse=True,
quota='governmental'
)
archives = WarehouseArchive.objects.filter(
kill_house=kill_house,
date__date=production_date,
quota='governmental',
trash=False
)
live_weight = kill_house_requests.aggregate(total=Sum('accepted_real_weight'))['total'] or 0
kill_house_requests_weight = kill_house_requests.aggregate(total=Sum('ware_house_accepted_real_weight'))[
'total'] or 0
kill_house_allocations_weight = kill_house_allocations.aggregate(total=Sum('real_weight_of_carcasses'))[
'total'] or 0
kill_house_free_sale_bars_weight = kill_house_free_sale_bars.aggregate(total=Sum('real_weight_of_carcasses'))[
'total'] or 0
segmentation_weight = segmentations.aggregate(total=Sum('weight'))['total'] or 0
archives_governmental_weight = archives.aggregate(total=Sum('weight'))['total'] or 0
total_output = kill_house_allocations_weight + kill_house_free_sale_bars_weight + segmentation_weight + archives_governmental_weight
total_remain = kill_house_requests_weight - total_output
nature = 'کشتارکن' if kill_house.killer else 'کشتارگاه'
name_with_phone = f"{kill_house.name} ({kill_house.kill_house_operator.user.mobile or '-'})"
city = kill_house.city_name or (kill_house.system_address.city if kill_house.system_address else '-')
kill_house_data.append({
'nature': nature,
'name_with_phone': name_with_phone,
'city': city,
'live_weight': to_locale_str(int(live_weight)),
'carcass_weight': to_locale_str(int(kill_house_requests_weight)),
'distribution_weight': to_locale_str(int(total_output)),
'remain_weight': to_locale_str(int(total_remain)),
})
guild_ids = list(Guilds.objects.filter(trash=False, steward=True, active=True).values_list('id', flat=True))
if guild_ids:
input_allocations_data = StewardAllocation.objects.filter(
to_steward_id__in=guild_ids,
date__date=yesterday,
trash=False,
receiver_state='accepted',
warehouse=True,
steward_warehouse=True,
).values('to_steward_id').annotate(total=Sum('real_weight_of_carcasses'))
input_free_bars_data = StewardFreeBarInformation.objects.filter(
steward_id__in=guild_ids,
date__date=yesterday,
trash=False,
warehouse=True,
).values('steward_id').annotate(total=Sum('weight_of_carcasses'))
output_allocations_data = StewardAllocation.objects.filter(
steward_id__in=guild_ids,
production_date__date=yesterday,
trash=False,
receiver_state__in=('pending', 'accepted'),
warehouse=True,
steward_warehouse=True,
).values('steward_id').annotate(total=Sum('real_weight_of_carcasses'))
free_sale_bars_data = StewardFreeSaleBarInformation.objects.filter(
steward_id__in=guild_ids,
production_date__date=yesterday,
trash=False,
warehouse=True,
).values('steward_id').annotate(total=Sum('weight_of_carcasses'))
input_weights = {item['to_steward_id']: item['total'] or 0 for item in input_allocations_data}
input_free_bar_weights = {item['steward_id']: item['total'] or 0 for item in input_free_bars_data}
output_allocations_weights = {item['steward_id']: item['total'] or 0 for item in output_allocations_data}
free_sale_bars_weights = {item['steward_id']: item['total'] or 0 for item in free_sale_bars_data}
guilds = Guilds.objects.filter(id__in=guild_ids).select_related('user')
steward_data = []
for guild in guilds:
guild_id = guild.id
total_input = (input_weights.get(guild_id, 0) + input_free_bar_weights.get(guild_id, 0))
total_output = (output_allocations_weights.get(guild_id, 0) + free_sale_bars_weights.get(guild_id, 0))
remain_weight = total_input - total_output
if total_output == 0 and total_input > 0:
unit_name = guild.guilds_name or '-'
user_fullname = guild.user.fullname if guild.user else '-'
user_phone = guild.user.mobile if guild.user else (guild.phone or '-')
name_with_phone = f"{user_fullname} ({user_phone})"
steward_data.append({
'unit_name': unit_name,
'name_with_phone': name_with_phone,
'input_weight': to_locale_str(int(total_input)),
'output_weight': to_locale_str(int(total_output)),
'remain_weight': to_locale_str(int(remain_weight)),
})
else:
steward_data = []
report_date = shamsi_date(datetime.datetime.now().date(), in_value=True)
report_date_number = f"{report_date.year:04d}{report_date.month:02d}{report_date.day:02d}"
yesterday_shamsi = shamsi_date(yesterday, in_value=True)
production_date_shamsi = shamsi_date(production_date, in_value=True)
# تقسیم مباشرین به صفحات 19 تایی
steward_pages = []
page_size = 19
for i in range(0, len(steward_data), page_size):
page_data = steward_data[i:i + page_size]
# اضافه کردن شماره ردیف برای هر صفحه
for idx, steward in enumerate(page_data):
steward['row_number'] = i + idx + 1
steward_pages.append(page_data)
# Debug: چاپ تعداد صفحات
print(f"Total stewards: {len(steward_data)}, Total pages: {len(steward_pages)}")
for idx, page in enumerate(steward_pages):
print(f"Page {idx + 1}: {len(page)} stewards")
html_content = render_to_string('kill_house_debt_report.html', {
'kill_houses': kill_house_data,
'steward_pages': steward_pages,
'report_date': report_date,
"number": report_date_number,
'total_count': len(kill_house_data),
'steward_count': len(steward_data),
'yesterday': yesterday_shamsi,
'production_date': production_date_shamsi,
})
html = HTML(string=html_content, base_url=request.build_absolute_uri())
css = CSS(string='''
@page {
margin: 3mm;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 25px;
background: transparent;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
th, td {
border: 1px solid #dc3545;
padding: 4px 5px;
text-align: center;
font-size: 12px;
background-color: transparent;
}
th {
background-color: #dc3545;
color: white;
font-weight: normal;
text-align: center;
}
.a4-container {
page-break-inside: avoid;
page-break-after: avoid;
}
div[style*="page-break-before"] {
page-break-before: always !important;
break-before: page !important;
height: 0;
margin: 0;
padding: 0;
}
''', font_config=font_config)
pdf_file = io.BytesIO()
html.write_pdf(pdf_file, stylesheets=[css], font_config=font_config)
pdf_file.seek(0)
response = HttpResponse(pdf_file, content_type='application/pdf')
filename = f'گزارش کشتارگاه‌های قفل شده - {report_date}.pdf'
encoded_filename = quote(filename)
response['Content-Disposition'] = f'attachment; filename*=UTF-8\'\'{encoded_filename}'
return response