patch oko teksta PDFa i UI tablica
This commit is contained in:
@@ -11,21 +11,13 @@ from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django.utils.html import escape
|
||||
from django.db.models import Q
|
||||
import os
|
||||
from reportlab.lib.pagesizes import A4
|
||||
from reportlab.lib import colors
|
||||
from reportlab.lib.utils import ImageReader
|
||||
from reportlab.lib.styles import getSampleStyleSheet
|
||||
from reportlab.pdfgen import canvas
|
||||
from reportlab.platypus import Table, TableStyle, Paragraph
|
||||
from reportlab.pdfbase import pdfmetrics
|
||||
from reportlab.pdfbase.ttfonts import TTFont
|
||||
|
||||
# Register Unicode-capable fonts (Vera supports HR characters: č, ć, đ, š, ž)
|
||||
_RL_FONTS_DIR = os.path.join(os.path.dirname(__import__('reportlab').__file__), 'fonts')
|
||||
pdfmetrics.registerFont(TTFont('Vera', os.path.join(_RL_FONTS_DIR, 'Vera.ttf')))
|
||||
pdfmetrics.registerFont(TTFont('Vera-Bold', os.path.join(_RL_FONTS_DIR, 'VeraBd.ttf')))
|
||||
pdfmetrics.registerFont(TTFont('Vera-Italic', os.path.join(_RL_FONTS_DIR, 'VeraIt.ttf')))
|
||||
from .pdf_layout import register_unicode_fonts, draw_standard_header_footer
|
||||
from rest_framework import viewsets, permissions, status
|
||||
from rest_framework.decorators import action, api_view, permission_classes
|
||||
from rest_framework.response import Response
|
||||
@@ -61,6 +53,8 @@ from .services import (
|
||||
)
|
||||
from .tasks import build_work_order_invoices_pdf_task
|
||||
|
||||
register_unicode_fonts()
|
||||
|
||||
def _fleet_assets_queryset_for_user(user, model, *, asset_type=None):
|
||||
queryset = model.objects.select_related('client', 'assigned_servicer').filter(is_active=True)
|
||||
if asset_type:
|
||||
@@ -226,6 +220,30 @@ def _build_work_order_pdf(work_order):
|
||||
place_label = (work_order.location or 'Zagreb').split(',')[0].strip() or 'Zagreb'
|
||||
invoice_names = [inv.naziv_racuna for inv in invoices[:5] if inv.naziv_racuna]
|
||||
attachments_text = ', '.join(invoice_names) if invoice_names else '-'
|
||||
assigned_servicer_vehicle = (
|
||||
creator.assigned_vehicles
|
||||
.filter(asset_type='vehicle', is_active=True)
|
||||
.order_by('registration_number')
|
||||
.first()
|
||||
)
|
||||
assigned_servicer_vehicle_label = "-"
|
||||
assigned_servicer_vehicle_registration = "-"
|
||||
if assigned_servicer_vehicle:
|
||||
assigned_servicer_vehicle_label = " ".join(
|
||||
part for part in [assigned_servicer_vehicle.make, assigned_servicer_vehicle.model] if part
|
||||
).strip() or assigned_servicer_vehicle.registration_number
|
||||
assigned_servicer_vehicle_registration = assigned_servicer_vehicle.registration_number or "-"
|
||||
|
||||
servicer_vehicle_label = (
|
||||
assigned_servicer_vehicle_label
|
||||
if assigned_servicer_vehicle
|
||||
else (work_order.servicer_vehicle_make_model or '-')
|
||||
)
|
||||
servicer_vehicle_registration = (
|
||||
assigned_servicer_vehicle_registration
|
||||
if assigned_servicer_vehicle
|
||||
else (work_order.servicer_vehicle_registration or '-')
|
||||
)
|
||||
|
||||
buffer = BytesIO()
|
||||
pdf = canvas.Canvas(buffer, pagesize=A4)
|
||||
@@ -331,7 +349,7 @@ def _build_work_order_pdf(work_order):
|
||||
[
|
||||
"1 dana" if travel_start else "-",
|
||||
_fmt_date(travel_start.date() if travel_start else work_order.date),
|
||||
f"{work_order.servicer_vehicle_make_model or '-'}, {work_order.servicer_vehicle_registration or '-'}",
|
||||
f"{servicer_vehicle_label}, {servicer_vehicle_registration}",
|
||||
],
|
||||
["Troškovi putovanja terete:", "Posebni dodaci (predujam):", "Početno stanje kilometara:"],
|
||||
[
|
||||
@@ -397,7 +415,7 @@ def _build_work_order_pdf(work_order):
|
||||
y,
|
||||
[
|
||||
["RELACIJA od", "RELACIJA do", "Vrsta prijevoznog sredstva", "Razred [km]", "Iznos za prijevoz", "Ukupan iznos"],
|
||||
[place_label or '-', work_order.location or '-', work_order.servicer_vehicle_make_model or '-', str(work_order.distance or 0), _fmt_eur(transport_total), _fmt_eur(transport_total)],
|
||||
[place_label or '-', work_order.location or '-', f"{servicer_vehicle_label}, {servicer_vehicle_registration}", str(work_order.distance or 0), _fmt_eur(transport_total), _fmt_eur(transport_total)],
|
||||
["", "", "", "", "", ""],
|
||||
["", "", "", "", "", ""],
|
||||
],
|
||||
@@ -493,7 +511,8 @@ def _build_work_order_pdf(work_order):
|
||||
def _build_work_order_service_records_pdf(work_order):
|
||||
vehicle = work_order.vehicle
|
||||
client_name = getattr(vehicle.client, 'name', None) or '-'
|
||||
model_str = ' '.join(filter(None, [vehicle.make, vehicle.model])) or '-'
|
||||
manufacturer_str = str(vehicle.make or '-')
|
||||
model_str = str(vehicle.model or '-')
|
||||
serial_str = str(vehicle.crane_serial_number or '-')
|
||||
upgrade_hours_str = str(getattr(vehicle, 'superstructure_working_hours', '-') or '-')
|
||||
chassis_hours_str = str(getattr(vehicle, 'chassis_working_hours', '-') or '-')
|
||||
@@ -563,86 +582,24 @@ def _build_work_order_service_records_pdf(work_order):
|
||||
super().save()
|
||||
|
||||
def _draw_header_footer(self):
|
||||
w, h = A4
|
||||
page_num = self._current_page
|
||||
|
||||
self.setStrokeColor(colors.black)
|
||||
self.setLineWidth(0.7)
|
||||
self.rect(MARGIN, h - HEADER_H, w - 2 * MARGIN, HEADER_H - 4, stroke=1, fill=0)
|
||||
|
||||
self.setFont("Vera-Bold", 11)
|
||||
self.drawString(MARGIN + 6, h - 22, client_name[:44])
|
||||
self.drawCentredString(w / 2, h - 22, "Izvještaj servisera")
|
||||
self.setFont("Vera", 9)
|
||||
self.drawRightString(w - MARGIN - 6, h - 22, f"Stranica {page_num}")
|
||||
|
||||
self.setLineWidth(0.5)
|
||||
self.line(MARGIN, h - 36, w - MARGIN, h - 36)
|
||||
|
||||
labels = [
|
||||
"Model:",
|
||||
"Serijski broj:",
|
||||
"Radni sati nadogradnje:",
|
||||
"Radni sati podvozja:",
|
||||
"Km:",
|
||||
"Broj naloga:",
|
||||
]
|
||||
values = [
|
||||
model_str,
|
||||
serial_str,
|
||||
upgrade_hours_str,
|
||||
chassis_hours_str,
|
||||
mileage_str,
|
||||
nalog_str,
|
||||
]
|
||||
col_w = (w - 2 * MARGIN) / len(labels)
|
||||
self.setFont("Vera", 7.2)
|
||||
for i, (lbl, val) in enumerate(zip(labels, values)):
|
||||
x = MARGIN + i * col_w + 3
|
||||
self.drawString(x, h - 49, lbl)
|
||||
value_text = str(val or '-')
|
||||
value_font_size = 9
|
||||
if i == len(labels) - 1:
|
||||
value_font_size = 7
|
||||
max_value_width = col_w - 8
|
||||
while (
|
||||
self.stringWidth(value_text, "Vera-Bold", value_font_size) > max_value_width
|
||||
and value_font_size > 5.5
|
||||
):
|
||||
value_font_size -= 0.3
|
||||
if self.stringWidth(value_text, "Vera-Bold", value_font_size) > max_value_width:
|
||||
trimmed = value_text
|
||||
while (
|
||||
len(trimmed) > 3
|
||||
and self.stringWidth(f"{trimmed}...", "Vera-Bold", value_font_size) > max_value_width
|
||||
):
|
||||
trimmed = trimmed[:-1]
|
||||
value_text = f"{trimmed}..."
|
||||
else:
|
||||
value_text = value_text[:24]
|
||||
self.setFont("Vera-Bold", value_font_size)
|
||||
self.drawString(x, h - 61, value_text)
|
||||
self.setFont("Vera", 7.2)
|
||||
if i > 0:
|
||||
self.line(MARGIN + i * col_w, h - 36, MARGIN + i * col_w, h - HEADER_H + 4)
|
||||
|
||||
footer_y = FOOTER_H
|
||||
self.setLineWidth(0.5)
|
||||
self.rect(MARGIN, footer_y + 42, w - 2 * MARGIN, 18, stroke=1, fill=0)
|
||||
sig_labels = [f"Datum: {generated_date_str}", "Potpis servisera", "Pečat i potpis klijenta *1", "Pregledao"]
|
||||
sig_w = (w - 2 * MARGIN) / 4
|
||||
self.setFont("Vera", 7.2)
|
||||
for i, lbl in enumerate(sig_labels):
|
||||
x = MARGIN + i * sig_w
|
||||
self.drawString(x + 4, footer_y + 45, lbl)
|
||||
if i > 0:
|
||||
self.line(x, footer_y + 42, x, footer_y + 60)
|
||||
self.setFont("Vera", 6.5)
|
||||
self.drawString(MARGIN, footer_y + 26, "*1- potpisom klijent potvrđuje da je suglasan s podacima u radnom nalogu")
|
||||
self.drawCentredString(
|
||||
w / 2,
|
||||
footer_y + 14,
|
||||
"Ovlašteni servis LIEBHERR Werk-Ehingen GmbH, LIEBHERR-Werk Nenzing GmbH, Liebherr-MCCTech Rostock GmbH",
|
||||
draw_standard_header_footer(
|
||||
self,
|
||||
page_num=page_num,
|
||||
client_name=client_name,
|
||||
manufacturer=manufacturer_str,
|
||||
model=model_str,
|
||||
serial=serial_str,
|
||||
upgrade_hours=upgrade_hours_str,
|
||||
chassis_hours=chassis_hours_str,
|
||||
mileage=mileage_str,
|
||||
work_order_number=nalog_str,
|
||||
generated_date=generated_date_str,
|
||||
report_title="Izvještaj servisera",
|
||||
page_size=A4,
|
||||
margin=MARGIN,
|
||||
header_h=HEADER_H,
|
||||
footer_h=FOOTER_H,
|
||||
)
|
||||
|
||||
pdf = PageCanvas(buffer, pagesize=A4)
|
||||
@@ -799,7 +756,7 @@ def _build_work_order_service_records_pdf(work_order):
|
||||
|
||||
if not related_tasks:
|
||||
pdf.setFont("Vera", 9)
|
||||
pdf.drawString(MARGIN, y, "Nema povezanih taskova za ovaj putni nalog.")
|
||||
pdf.drawString(MARGIN, y, "Nema povezanih servisnih zadataka za ovaj putni nalog.")
|
||||
else:
|
||||
for task in related_tasks:
|
||||
task_records = [
|
||||
@@ -812,7 +769,7 @@ def _build_work_order_service_records_pdf(work_order):
|
||||
if y < content_bottom + 60:
|
||||
y = new_page()
|
||||
pdf.setFont("Vera-Bold", 10)
|
||||
pdf.drawString(MARGIN, y, (task.title or f"Task #{task.id}")[:95])
|
||||
pdf.drawString(MARGIN, y, (task.title or f"Servisni zadatak #{task.id}")[:95])
|
||||
y -= 14
|
||||
|
||||
for record in task_records:
|
||||
@@ -912,6 +869,247 @@ def _build_work_order_service_records_pdf(work_order):
|
||||
pdf.save()
|
||||
return buffer.getvalue()
|
||||
|
||||
|
||||
def _build_service_record_pdf(service_record):
|
||||
vehicle = service_record.vehicle
|
||||
task = getattr(service_record, 'task', None)
|
||||
work_order = getattr(task, 'work_order', None) if task else None
|
||||
client_name = getattr(getattr(vehicle, 'client', None), 'name', None) or '-'
|
||||
manufacturer_str = str(vehicle.make or '-')
|
||||
model_str = str(vehicle.model or '-')
|
||||
serial_str = str(vehicle.crane_serial_number or '-')
|
||||
upgrade_hours_str = str(getattr(vehicle, 'superstructure_working_hours', '-') or '-')
|
||||
chassis_hours_str = str(getattr(vehicle, 'chassis_working_hours', '-') or '-')
|
||||
mileage_str = str(vehicle.current_mileage or '-')
|
||||
nalog_str = str(getattr(work_order, 'pk', '-') or '-')
|
||||
generated_date_str = timezone.localtime(timezone.now()).strftime('%d.%m.%Y')
|
||||
|
||||
HEADER_H = 86
|
||||
FOOTER_H = 72
|
||||
MARGIN = 28
|
||||
|
||||
def _fmt_date(value):
|
||||
if not value:
|
||||
return '-'
|
||||
return value.strftime('%d.%m.%Y') if hasattr(value, 'strftime') else str(value)
|
||||
|
||||
buffer = BytesIO()
|
||||
|
||||
class PageCanvas(canvas.Canvas):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self._current_page = 0
|
||||
|
||||
def showPage(self):
|
||||
self._current_page += 1
|
||||
self._draw_header_footer()
|
||||
super().showPage()
|
||||
|
||||
def save(self):
|
||||
self._current_page += 1
|
||||
self._draw_header_footer()
|
||||
super().save()
|
||||
|
||||
def _draw_header_footer(self):
|
||||
page_num = self._current_page
|
||||
draw_standard_header_footer(
|
||||
self,
|
||||
page_num=page_num,
|
||||
client_name=client_name,
|
||||
manufacturer=manufacturer_str,
|
||||
model=model_str,
|
||||
serial=serial_str,
|
||||
upgrade_hours=upgrade_hours_str,
|
||||
chassis_hours=chassis_hours_str,
|
||||
mileage=mileage_str,
|
||||
work_order_number=nalog_str,
|
||||
generated_date=generated_date_str,
|
||||
report_title="Izvještaj servisera",
|
||||
page_size=A4,
|
||||
margin=MARGIN,
|
||||
header_h=HEADER_H,
|
||||
footer_h=FOOTER_H,
|
||||
)
|
||||
|
||||
pdf = PageCanvas(buffer, pagesize=A4)
|
||||
page_w, page_h = A4
|
||||
content_top = page_h - HEADER_H - 10
|
||||
content_bottom = FOOTER_H + 52
|
||||
content_width = page_w - 2 * MARGIN
|
||||
|
||||
def new_page():
|
||||
pdf.showPage()
|
||||
return content_top
|
||||
|
||||
def draw_table(y, data, col_widths, style, row_heights=None):
|
||||
table = Table(data, colWidths=col_widths, rowHeights=row_heights)
|
||||
table.setStyle(style)
|
||||
_, h = table.wrap(content_width, page_h)
|
||||
if y - h < content_bottom:
|
||||
y = new_page()
|
||||
table.drawOn(pdf, MARGIN, y - h)
|
||||
return y - h - 10
|
||||
|
||||
paragraph_styles = getSampleStyleSheet()
|
||||
description_style = paragraph_styles['BodyText'].clone('service-record-description')
|
||||
description_style.fontName = 'Vera'
|
||||
description_style.fontSize = 8.2
|
||||
description_style.leading = 10.4
|
||||
|
||||
y = content_top - 6
|
||||
y -= 6
|
||||
|
||||
info_rows = [
|
||||
["ID", str(service_record.pk), "Datum", _fmt_date(service_record.service_date)],
|
||||
["Naziv", service_record.service_title or '-', "Servisni zadatak", getattr(task, 'title', '-') or '-'],
|
||||
["Dizalica", getattr(vehicle, 'registration_number', '-') or '-', "SN", getattr(vehicle, 'crane_serial_number', '-') or '-'],
|
||||
["Serviser", _user_display_name(service_record.performed_by) or '-', "KM", str(service_record.mileage or '-')],
|
||||
["Trošak", str(service_record.cost), "Sljedeći servis", str(service_record.next_service_due_at or '-')],
|
||||
]
|
||||
y = draw_table(
|
||||
y,
|
||||
info_rows,
|
||||
[78, content_width * 0.37, 88, content_width - 166 - (content_width * 0.37)],
|
||||
TableStyle([
|
||||
('FONTNAME', (0, 0), (-1, -1), 'Vera'),
|
||||
('FONTNAME', (0, 0), (0, -1), 'Vera-Bold'),
|
||||
('FONTNAME', (2, 0), (2, -1), 'Vera-Bold'),
|
||||
('FONTSIZE', (0, 0), (-1, -1), 8.5),
|
||||
('GRID', (0, 0), (-1, -1), 0.5, colors.black),
|
||||
('VALIGN', (0, 0), (-1, -1), 'TOP'),
|
||||
('LEFTPADDING', (0, 0), (-1, -1), 4),
|
||||
('RIGHTPADDING', (0, 0), (-1, -1), 4),
|
||||
('TOPPADDING', (0, 0), (-1, -1), 4),
|
||||
('BOTTOMPADDING', (0, 0), (-1, -1), 4),
|
||||
]),
|
||||
)
|
||||
|
||||
y = draw_table(
|
||||
y,
|
||||
[["Servisni opis"], [Paragraph(service_record.description or '-', description_style)]],
|
||||
[content_width],
|
||||
TableStyle([
|
||||
('FONTNAME', (0, 0), (-1, 0), 'Vera-Bold'),
|
||||
('FONTNAME', (0, 1), (-1, -1), 'Vera'),
|
||||
('FONTSIZE', (0, 0), (-1, -1), 8.2),
|
||||
('GRID', (0, 0), (-1, -1), 0.5, colors.black),
|
||||
('VALIGN', (0, 0), (-1, -1), 'TOP'),
|
||||
('LEFTPADDING', (0, 0), (-1, -1), 4),
|
||||
('RIGHTPADDING', (0, 0), (-1, -1), 4),
|
||||
('TOPPADDING', (0, 0), (-1, -1), 4),
|
||||
('BOTTOMPADDING', (0, 0), (-1, -1), 4),
|
||||
]),
|
||||
)
|
||||
|
||||
y = draw_table(
|
||||
y,
|
||||
[["Korišteni dijelovi"], [Paragraph(service_record.parts or '-', description_style)]],
|
||||
[content_width],
|
||||
TableStyle([
|
||||
('FONTNAME', (0, 0), (-1, 0), 'Vera-Bold'),
|
||||
('FONTNAME', (0, 1), (-1, -1), 'Vera'),
|
||||
('FONTSIZE', (0, 0), (-1, -1), 8.2),
|
||||
('GRID', (0, 0), (-1, -1), 0.5, colors.black),
|
||||
('VALIGN', (0, 0), (-1, -1), 'TOP'),
|
||||
('LEFTPADDING', (0, 0), (-1, -1), 4),
|
||||
('RIGHTPADDING', (0, 0), (-1, -1), 4),
|
||||
('TOPPADDING', (0, 0), (-1, -1), 4),
|
||||
('BOTTOMPADDING', (0, 0), (-1, -1), 4),
|
||||
]),
|
||||
)
|
||||
|
||||
attachments = list(service_record.attachments.filter(is_active=True).all())
|
||||
attachment_names = [os.path.basename(item.file.name) for item in attachments if item.file]
|
||||
y = draw_table(
|
||||
y,
|
||||
[["Prilozi"], [Paragraph(', '.join(attachment_names) if attachment_names else '-', description_style)]],
|
||||
[content_width],
|
||||
TableStyle([
|
||||
('FONTNAME', (0, 0), (-1, 0), 'Vera-Bold'),
|
||||
('FONTNAME', (0, 1), (-1, -1), 'Vera'),
|
||||
('FONTSIZE', (0, 0), (-1, -1), 8.2),
|
||||
('GRID', (0, 0), (-1, -1), 0.5, colors.black),
|
||||
('VALIGN', (0, 0), (-1, -1), 'TOP'),
|
||||
('LEFTPADDING', (0, 0), (-1, -1), 4),
|
||||
('RIGHTPADDING', (0, 0), (-1, -1), 4),
|
||||
('TOPPADDING', (0, 0), (-1, -1), 4),
|
||||
('BOTTOMPADDING', (0, 0), (-1, -1), 4),
|
||||
]),
|
||||
)
|
||||
|
||||
photos = [photo for photo in service_record.photos.filter(is_active=True).all() if photo.image]
|
||||
if photos:
|
||||
if y < content_bottom + 30:
|
||||
y = new_page()
|
||||
y -= 8
|
||||
pdf.setFont("Vera", 8)
|
||||
pdf.drawString(MARGIN, y, "Fotografije:")
|
||||
y -= 10
|
||||
|
||||
image_gap = 10
|
||||
max_image_height = 110
|
||||
image_width = (content_width - image_gap) / 2
|
||||
for index in range(0, len(photos), 2):
|
||||
row_photos = photos[index:index + 2]
|
||||
prepared = []
|
||||
for photo in row_photos:
|
||||
try:
|
||||
image_reader = ImageReader(photo.image)
|
||||
source_w, source_h = image_reader.getSize()
|
||||
if not source_w or not source_h:
|
||||
continue
|
||||
scaled_h = min(max_image_height, image_width * (float(source_h) / float(source_w)))
|
||||
prepared.append((photo, image_reader, scaled_h))
|
||||
except (OSError, ValueError, TypeError, UnidentifiedImageError):
|
||||
continue
|
||||
if not prepared:
|
||||
continue
|
||||
|
||||
caption_height = 12
|
||||
row_height = max(item[2] for item in prepared) + caption_height
|
||||
if y - row_height < content_bottom:
|
||||
y = new_page()
|
||||
|
||||
base_y = y - caption_height
|
||||
for photo_index, (photo, image_reader, scaled_h) in enumerate(prepared):
|
||||
image_x = MARGIN + photo_index * (image_width + image_gap)
|
||||
image_y = base_y - scaled_h
|
||||
pdf.drawImage(
|
||||
image_reader,
|
||||
image_x,
|
||||
image_y,
|
||||
width=image_width,
|
||||
height=scaled_h,
|
||||
preserveAspectRatio=True,
|
||||
anchor='c',
|
||||
mask='auto',
|
||||
)
|
||||
pdf.setFont("Vera", 7)
|
||||
caption = (photo.description or '').strip() or f"Slika {index + photo_index + 1}"
|
||||
pdf.drawString(image_x, image_y - 10, caption[:52])
|
||||
|
||||
y = base_y - max(item[2] for item in prepared) - 14
|
||||
else:
|
||||
y = draw_table(
|
||||
y,
|
||||
[["Fotografije"], ["-"]],
|
||||
[content_width],
|
||||
TableStyle([
|
||||
('FONTNAME', (0, 0), (-1, 0), 'Vera-Bold'),
|
||||
('FONTNAME', (0, 1), (-1, -1), 'Vera'),
|
||||
('FONTSIZE', (0, 0), (-1, -1), 8.2),
|
||||
('GRID', (0, 0), (-1, -1), 0.5, colors.black),
|
||||
('VALIGN', (0, 0), (-1, -1), 'TOP'),
|
||||
('LEFTPADDING', (0, 0), (-1, -1), 4),
|
||||
('RIGHTPADDING', (0, 0), (-1, -1), 4),
|
||||
('TOPPADDING', (0, 0), (-1, -1), 4),
|
||||
('BOTTOMPADDING', (0, 0), (-1, -1), 4),
|
||||
]),
|
||||
)
|
||||
|
||||
pdf.save()
|
||||
return buffer.getvalue()
|
||||
|
||||
def _first_non_empty(*values):
|
||||
for value in values:
|
||||
if isinstance(value, str) and value.strip():
|
||||
@@ -1294,18 +1492,7 @@ class VehicleServiceRecordViewSet(viewsets.ModelViewSet):
|
||||
@action(detail=True, methods=['get'], url_path='pdf')
|
||||
def pdf(self, request, pk=None):
|
||||
service_record = self.get_object()
|
||||
rows = [
|
||||
("ID", str(service_record.pk)),
|
||||
("Datum", str(service_record.service_date)),
|
||||
("Dizalica", service_record.vehicle.registration_number),
|
||||
("Serviser", service_record.performed_by.get_full_name() or service_record.performed_by.email),
|
||||
("Kilometraza", str(service_record.mileage)),
|
||||
("Sljedeci servis", str(service_record.next_service_due_at or '-')),
|
||||
("Trosak", str(service_record.cost)),
|
||||
("Opis", service_record.description or '-'),
|
||||
("Dijelovi", service_record.parts or '-'),
|
||||
]
|
||||
pdf_bytes = _build_simple_pdf(f"Servisni zapis {service_record.pk}", rows)
|
||||
pdf_bytes = _build_service_record_pdf(service_record)
|
||||
response = HttpResponse(pdf_bytes, content_type='application/pdf')
|
||||
response['Content-Disposition'] = f'attachment; filename="{service_record.pk}.service-record.pdf"'
|
||||
return response
|
||||
@@ -1321,16 +1508,7 @@ class VehicleServiceRecordViewSet(viewsets.ModelViewSet):
|
||||
if not recipient:
|
||||
raise DRFValidationError({"recipient": "Nije pronađena email adresa za slanje."})
|
||||
|
||||
rows = [
|
||||
("ID", str(service_record.pk)),
|
||||
("Datum", str(service_record.service_date)),
|
||||
("Dizalica", service_record.vehicle.registration_number),
|
||||
("Kilometraza", str(service_record.mileage)),
|
||||
("Trosak", str(service_record.cost)),
|
||||
("Opis", service_record.description or '-'),
|
||||
("Dijelovi", service_record.parts or '-'),
|
||||
]
|
||||
pdf_bytes = _build_simple_pdf(f"Servisni zapis {service_record.pk}", rows)
|
||||
pdf_bytes = _build_service_record_pdf(service_record)
|
||||
subject = _first_non_empty(request.data.get('subject')) or f"Servisni zapis {service_record.pk}"
|
||||
body = _first_non_empty(request.data.get('message')) or (
|
||||
f"U prilogu je PDF servisnog zapisa. Poslano {timezone.now().strftime('%d.%m.%Y %H:%M')}."
|
||||
|
||||
Reference in New Issue
Block a user