diff --git a/backend/modules/fleet/views.py b/backend/modules/fleet/views.py index 77e6881..06ab767 100644 --- a/backend/modules/fleet/views.py +++ b/backend/modules/fleet/views.py @@ -210,6 +210,32 @@ def _docx_filename(work_order, doc_type): return f"{display_code}.work-order.docx" +def _service_records_pdf_filename(work_order, task=None): + if not task: + return _pdf_filename(work_order, 'service_records') + display_code = _work_order_display_code(work_order) + return f"{display_code}.task-{task.pk}.work-order-service-records.pdf" + + +def _service_records_docx_filename(work_order, task=None): + if not task: + return _docx_filename(work_order, 'service_records') + display_code = _work_order_display_code(work_order) + return f"{display_code}.task-{task.pk}.work-order-service-records.docx" + + +def _resolve_service_report_tasks(work_order, task_id): + queryset = _work_order_related_tasks_queryset(work_order) + if not task_id: + return list(queryset), None + selected_task = queryset.filter(pk=task_id).first() + if not selected_task: + raise DRFValidationError({ + 'task_id': 'Odabrani task nije povezan s ovim putnim nalogom.' + }) + return [selected_task], selected_task + + def _compress_image_for_pdf(image_field, max_width=1280, quality=75): """ Otvori image_field (Django FileField), kompresiraj na max_width JPEG u memoriji, @@ -884,7 +910,7 @@ def _build_work_order_pdf(work_order): return buffer.getvalue() -def _build_work_order_service_records_pdf(work_order): +def _build_work_order_service_records_pdf(work_order, related_tasks=None): vehicle = work_order.vehicle client_name = getattr(vehicle.client, 'name', None) or '-' manufacturer_str = str(vehicle.make or '-') @@ -900,7 +926,10 @@ def _build_work_order_service_records_pdf(work_order): FOOTER_H = 72 MARGIN = 28 - related_tasks = list(_work_order_related_tasks_queryset(work_order)) + if related_tasks is None: + related_tasks = list(_work_order_related_tasks_queryset(work_order)) + else: + related_tasks = list(related_tasks) # Collect service records for all task vehicles (supports cross-crane work orders) task_vehicle_ids = list({task.vehicle_id for task in related_tasks if task.vehicle_id}) service_rows = list( @@ -1812,7 +1841,7 @@ def _build_work_order_docx_bytes(work_order): return buffer.getvalue() -def _build_work_order_service_records_docx_bytes(work_order): +def _build_work_order_service_records_docx_bytes(work_order, related_tasks=None): from docx.shared import Cm doc = _create_docx_document(SERVICE_REPORT_DOCX_TEMPLATE_NAME) @@ -1821,7 +1850,10 @@ def _build_work_order_service_records_docx_bytes(work_order): servicer_name = _user_display_name(work_order.creator) or '-' completion_label = "Da ☒ Ne ☐" if work_order.status == 'closed' else "Da ☐ Ne ☒" - related_tasks = list(_work_order_related_tasks_queryset(work_order).select_related('work_hours_table')) + if related_tasks is None: + related_tasks = list(_work_order_related_tasks_queryset(work_order).select_related('work_hours_table')) + else: + related_tasks = list(related_tasks) normalized_rows = [] for task in related_tasks: table_data = getattr(getattr(task, 'work_hours_table', None), 'data', None) @@ -2792,27 +2824,38 @@ class WorkOrderViewSet(viewsets.ModelViewSet): @action(detail=True, methods=['get'], url_path='service-records-pdf') def service_records_pdf(self, request, pk=None): work_order = self.get_object() - _cleanup_expired_generated_pdfs() - cached = _get_cached_pdf(work_order, 'service_records') - if cached: - return _cached_pdf_file_response(cached, default_filename=_pdf_filename(work_order, 'service_records')) + task_id = request.query_params.get('task_id') + related_tasks, selected_task = _resolve_service_report_tasks(work_order, task_id) - _notify_pdf_request(user=request.user, work_order=work_order, doc_type='service_records', stage='requested') - pdf_bytes = _build_work_order_service_records_pdf(work_order) - _notify_pdf_request(user=request.user, work_order=work_order, doc_type='service_records', stage='completed') + if not selected_task: + _cleanup_expired_generated_pdfs() + cached = _get_cached_pdf(work_order, 'service_records') + if cached: + return _cached_pdf_file_response( + cached, + default_filename=_service_records_pdf_filename(work_order), + ) + _notify_pdf_request(user=request.user, work_order=work_order, doc_type='service_records', stage='requested') + + pdf_bytes = _build_work_order_service_records_pdf(work_order, related_tasks=related_tasks) + + if not selected_task: + _notify_pdf_request(user=request.user, work_order=work_order, doc_type='service_records', stage='completed') response = HttpResponse(pdf_bytes, content_type='application/pdf') - response['Content-Disposition'] = f'attachment; filename="{_pdf_filename(work_order, "service_records")}"' + response['Content-Disposition'] = f'attachment; filename="{_service_records_pdf_filename(work_order, selected_task)}"' return response @action(detail=True, methods=['get'], url_path='service-records-docx') def service_records_docx(self, request, pk=None): work_order = self.get_object() - docx_bytes = _build_work_order_service_records_docx_bytes(work_order) + task_id = request.query_params.get('task_id') + related_tasks, selected_task = _resolve_service_report_tasks(work_order, task_id) + docx_bytes = _build_work_order_service_records_docx_bytes(work_order, related_tasks=related_tasks) response = HttpResponse( docx_bytes, content_type='application/vnd.openxmlformats-officedocument.wordprocessingml.document', ) - response['Content-Disposition'] = f'attachment; filename="{_docx_filename(work_order, "service_records")}"' + response['Content-Disposition'] = f'attachment; filename="{_service_records_docx_filename(work_order, selected_task)}"' return response @action(detail=True, methods=['post'], url_path='service-records-pdf-request') diff --git a/frontend/src/components/dashboard/WorkOrderInvoicesPdfPage.jsx b/frontend/src/components/dashboard/WorkOrderInvoicesPdfPage.jsx index fbf02b5..b6c12e6 100644 --- a/frontend/src/components/dashboard/WorkOrderInvoicesPdfPage.jsx +++ b/frontend/src/components/dashboard/WorkOrderInvoicesPdfPage.jsx @@ -350,7 +350,7 @@ export default function WorkOrderInvoicesPdfPage() { disabled={!workOrderId} className="rounded-lg bg-indigo-600 px-4 py-2 text-sm font-semibold text-white hover:bg-indigo-700 disabled:opacity-60" > - Preuzmi PDF servisnih zapisa + Preuzmi PDF svih servisnih zapisa @@ -397,6 +397,22 @@ export default function WorkOrderInvoicesPdfPage() { > Uredi tekst napomene + +