fix: restore archive downloads and task report context
Some checks failed
ERP CI/CD Pipeline / test (push) Has been cancelled
ERP CI/CD Pipeline / Deploy (server git pull + compose) (push) Has been cancelled

Restore the monthly fleet archive task and routes so generated ZIP downloads work again. Also populate service report DOCX headers from the selected task/work-order context and cover the direct and archived export flows with regression tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
mariomitte
2026-08-06 20:37:30 +02:00
parent ed71bf500f
commit 925cd25d98
5 changed files with 196 additions and 207 deletions

View File

@@ -836,23 +836,72 @@ def process_work_order_invoice_ocr(invoice_id):
@shared_task
def cleanup_expired_generated_pdfs_task():
now = timezone.now()
expired = GeneratedWorkOrderPdf.objects.filter(
is_active=True,
expires_at__isnull=False,
expires_at__lte=now,
def build_monthly_archive_cached_task(generated_archive_id):
from .models import GeneratedFleetArchive
from .services import NotificationService
from .views import (
_build_monthly_service_tasks_archive_content,
_build_monthly_work_orders_archive_content,
_notify_monthly_archive_request,
)
deleted = 0
for item in expired:
if item.file:
item.file.delete(save=False)
item.is_active = False
item.status = 'failed'
item.error_message = 'PDF cache istekao.'
item.save(update_fields=['is_active', 'status', 'error_message', 'updated_at'])
deleted += 1
return {"deleted": deleted}
generated = (
GeneratedFleetArchive.objects
.select_related('requested_by')
.filter(pk=generated_archive_id, is_active=True)
.first()
)
if generated is None:
return {"status": "failed", "error": "Generated archive record not found"}
try:
if generated.archive_type == 'service_tasks':
archive_content = _build_monthly_service_tasks_archive_content(
user=generated.requested_by,
year=generated.year,
month=generated.month,
)
else:
archive_content = _build_monthly_work_orders_archive_content(
user=generated.requested_by,
year=generated.year,
month=generated.month,
)
if not archive_content:
raise ValueError('ZIP arhiva je prazna.')
filename = generated.filename or f"{generated.archive_type}-{generated.year}-{generated.month}.zip"
generated.file.save(filename, ContentFile(archive_content), save=False)
generated.status = 'ready'
generated.error_message = ''
generated.save(update_fields=['file', 'status', 'error_message', 'updated_at'])
if generated.requested_by:
_notify_monthly_archive_request(
user=generated.requested_by,
archive_type=generated.archive_type,
stage='completed',
year=generated.year,
month=generated.month,
generated_archive=generated,
)
return {"status": "ready", "generated_archive_id": str(generated.pk)}
except Exception as exc:
generated.status = 'failed'
generated.error_message = str(exc)
generated.save(update_fields=['status', 'error_message', 'updated_at'])
if generated.requested_by:
_notify_monthly_archive_request(
user=generated.requested_by,
archive_type=generated.archive_type,
stage='failed',
year=generated.year,
month=generated.month,
generated_archive=generated,
)
logger.exception("Greška kod build_monthly_archive_cached_task: %s", exc)
return {"status": "failed", "error": str(exc)}
@shared_task
@@ -875,6 +924,26 @@ def cleanup_expired_generated_archives_task():
return {"deleted": deleted}
@shared_task
def cleanup_expired_generated_pdfs_task():
now = timezone.now()
expired = GeneratedWorkOrderPdf.objects.filter(
is_active=True,
expires_at__isnull=False,
expires_at__lte=now,
)
deleted = 0
for item in expired:
if item.file:
item.file.delete(save=False)
item.is_active = False
item.status = 'failed'
item.error_message = 'PDF cache istekao.'
item.save(update_fields=['is_active', 'status', 'error_message', 'updated_at'])
deleted += 1
return {"deleted": deleted}
@shared_task
def build_work_order_pdf_cached_task(generated_pdf_id):
from .views import _build_work_order_pdf, _build_work_order_service_records_pdf
@@ -954,98 +1023,4 @@ def build_work_order_pdf_cached_task(generated_pdf_id):
},
)
logger.exception("Greška kod build_work_order_pdf_cached_task: %s", exc)
return {"status": "failed", "error": str(exc)}
@shared_task
def build_monthly_archive_cached_task(generated_archive_id):
from .services import NotificationService
from .views import (
_build_monthly_service_tasks_archive_content,
_build_monthly_work_orders_archive_content,
_generated_archive_filename_for_user,
)
generated = (
GeneratedFleetArchive.objects
.select_related('requested_by')
.filter(pk=generated_archive_id, is_active=True)
.first()
)
if generated is None:
return {'error': 'Generated ZIP zapis nije pronađen.'}
requested_by = generated.requested_by
if requested_by is None:
generated.status = 'failed'
generated.error_message = 'Korisnik koji je zatražio ZIP arhivu nije dostupan.'
generated.save(update_fields=['status', 'error_message', 'updated_at'])
return {'status': 'failed', 'error': generated.error_message}
try:
if generated.archive_type == 'work_orders':
archive_bytes = _build_monthly_work_orders_archive_content(
user=requested_by,
year=generated.year,
month=generated.month,
)
else:
archive_bytes = _build_monthly_service_tasks_archive_content(
user=requested_by,
year=generated.year,
month=generated.month,
)
filename = generated.filename or _generated_archive_filename_for_user(
requested_by,
year=generated.year,
month=generated.month,
archive_type=generated.archive_type,
)
generated.file.save(filename, ContentFile(archive_bytes), save=False)
generated.status = 'ready'
generated.error_message = ''
generated.save(update_fields=['file', 'status', 'error_message', 'updated_at'])
NotificationService.create_notification(
recipient=requested_by,
title='ZIP arhiva spremna',
message=f"ZIP arhiva je spremna za preuzimanje ({generated.month:02d}.{generated.year}.).",
level='success',
send_email=False,
metadata={
'entity_type': 'fleet_archive',
'archive_type': generated.archive_type,
'stage': 'completed',
'year': generated.year,
'month': generated.month,
'generated_archive_id': str(generated.pk),
'download_url': f"fleet/reports/generated-archives/{generated.pk}/download/",
'filename': generated.filename or filename,
'expires_at': generated.expires_at.isoformat() if generated.expires_at else None,
'section': 'service-records',
},
)
return {'status': 'ready', 'generated_archive_id': str(generated.pk)}
except Exception as exc:
generated.status = 'failed'
generated.error_message = str(exc)
generated.save(update_fields=['status', 'error_message', 'updated_at'])
NotificationService.create_notification(
recipient=requested_by,
title='Greška kod ZIP arhive',
message=f"Generiranje ZIP arhive nije uspjelo ({generated.month:02d}.{generated.year}.).",
level='warning',
send_email=False,
metadata={
'entity_type': 'fleet_archive',
'archive_type': generated.archive_type,
'stage': 'failed',
'year': generated.year,
'month': generated.month,
'generated_archive_id': str(generated.pk),
'section': 'service-records',
},
)
logger.exception("Greška kod build_monthly_archive_cached_task: %s", exc)
return {'status': 'failed', 'error': str(exc)}
return {"status": "failed", "error": str(exc)}