feat: async PDF cache i API media putanje za putne naloge
Uvodi background request tok za generiranje PDF-a s 24h cache-om i cleanup taskom preko Celery beat-a. Dodaje notification metadata download_url za ponovno preuzimanje bez regeneracije, API image endpointe za putne naloge i račune, te frontend integraciju za async download i produkcijski prikaz slika. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -54,6 +54,15 @@ def _work_order_photo_upload_to(instance, filename):
|
||||
unique_name = f"{uuid.uuid4().hex}_{filename}"
|
||||
return f"fleet/{vehicle_reg}/work_order_photos/{unique_name}"
|
||||
|
||||
def _generated_work_order_pdf_upload_to(instance, filename):
|
||||
vehicle_reg = 'unknown'
|
||||
try:
|
||||
vehicle_reg = instance.work_order.vehicle.registration_number
|
||||
except Exception:
|
||||
vehicle_reg = 'unknown'
|
||||
unique_name = f"{uuid.uuid4().hex}_{filename}"
|
||||
return f"fleet/{vehicle_reg}/generated_pdfs/{unique_name}"
|
||||
|
||||
|
||||
class VehicleServicePhoto(BaseModel):
|
||||
"""
|
||||
@@ -384,6 +393,48 @@ class WorkOrderPhoto(BaseModel):
|
||||
return f"WorkOrderPhoto {self.pk} ({self.work_order_id})"
|
||||
|
||||
|
||||
class GeneratedWorkOrderPdf(BaseModel):
|
||||
PDF_TYPE_CHOICES = [
|
||||
('work_order', _("Putni nalog")),
|
||||
('service_records', _("Servisni zapisi")),
|
||||
('invoices', _("Računi")),
|
||||
]
|
||||
STATUS_CHOICES = [
|
||||
('pending', _("U obradi")),
|
||||
('ready', _("Spremno")),
|
||||
('failed', _("Neuspješno")),
|
||||
]
|
||||
|
||||
work_order = models.ForeignKey(
|
||||
WorkOrder,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='generated_pdfs',
|
||||
verbose_name=_("Putni nalog"),
|
||||
)
|
||||
requested_by = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
null=True,
|
||||
blank=True,
|
||||
on_delete=models.SET_NULL,
|
||||
related_name='requested_generated_work_order_pdfs',
|
||||
verbose_name=_("Zatražio"),
|
||||
)
|
||||
pdf_type = models.CharField(max_length=32, choices=PDF_TYPE_CHOICES, db_index=True, verbose_name=_("Tip PDF-a"))
|
||||
status = models.CharField(max_length=16, choices=STATUS_CHOICES, default='pending', db_index=True, verbose_name=_("Status"))
|
||||
file = models.FileField(upload_to=_generated_work_order_pdf_upload_to, null=True, blank=True, verbose_name=_("PDF datoteka"))
|
||||
filename = models.CharField(max_length=255, blank=True, verbose_name=_("Naziv datoteke"))
|
||||
expires_at = models.DateTimeField(null=True, blank=True, db_index=True, verbose_name=_("Vrijedi do"))
|
||||
error_message = models.TextField(blank=True, verbose_name=_("Poruka greške"))
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Generirani PDF putnog naloga")
|
||||
verbose_name_plural = _("Generirani PDF-ovi putnih naloga")
|
||||
ordering = ['-created_at']
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.pdf_type}:{self.work_order_id}:{self.status}"
|
||||
|
||||
|
||||
class VehicleServiceRecord(BaseModel):
|
||||
"""
|
||||
Zapisi o servisima/popravcima na vozilu.
|
||||
|
||||
Reference in New Issue
Block a user