feat: update service report exports and calendar bulk downloads
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

Align service-record PDF/DOCX generation with task-level data and naming.

- Use Task.service_report_note as report note source
- Use Task.scheduled_date for service-record dates
- Rename per-task exports to MT...SN... format
- Add monthly SN/PN ZIP download endpoints with 7-day retention
- Add calendar 'Preuzmi sve' modal with both bulk download actions
- Prefill work-hours day/date from scheduled_date for empty tables
- Remove duplicate note table and clean extra DOCX page breaks

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
mariomitte
2026-08-06 10:32:03 +02:00
parent 9a7c7e3163
commit 594881f6cd
7 changed files with 474 additions and 44 deletions

View File

@@ -865,7 +865,7 @@ export async function downloadWorkOrderInvoicesPdf(workOrderId) {
return payload;
}
export async function downloadWorkOrderServiceRecordsPdf(workOrderId, taskId = null) {
export async function downloadWorkOrderServiceRecordsPdf(workOrderId, taskId = null, taskOptions = {}) {
if (!workOrderId) {
throw new Error('Work order ID je obavezan.');
}
@@ -875,7 +875,12 @@ export async function downloadWorkOrderServiceRecordsPdf(workOrderId, taskId = n
`fleet/work-orders/${encodeURIComponent(workOrderId)}/service-records-pdf/?task_id=${encodeURIComponent(taskId)}`,
{ responseType: 'blob' },
);
saveBlobToFile(blob, `${workOrderId}.task-${taskId}.work-order-service-records.pdf`);
const workOrderDisplayCode = String(taskOptions?.workOrderDisplayCode || '').trim().toUpperCase() || String(workOrderId);
const taskTitle = String(taskOptions?.taskTitle || '').trim()
.replace(/\s+/g, '_')
.replace(/[^A-Za-z0-9_-]+/g, '')
.replace(/^[_\-.]+|[_\-.]+$/g, '') || `task-${taskId}`;
saveBlobToFile(blob, `${workOrderDisplayCode}.SN-${taskTitle}.pdf`);
showToast('PDF servisnih zapisa za odabrani task je preuzet.', 'success');
return;
} catch (err) {
@@ -912,7 +917,7 @@ export async function downloadWorkOrderDocx(workOrderId) {
}
}
export async function downloadWorkOrderServiceRecordsDocx(workOrderId, taskId = null) {
export async function downloadWorkOrderServiceRecordsDocx(workOrderId, taskId = null, taskOptions = {}) {
if (!workOrderId) {
throw new Error('Work order ID je obavezan.');
}
@@ -923,7 +928,12 @@ export async function downloadWorkOrderServiceRecordsDocx(workOrderId, taskId =
{ responseType: 'blob' },
);
if (taskId) {
saveBlobToFile(blob, `${workOrderId}.task-${taskId}.work-order-service-records.docx`);
const workOrderDisplayCode = String(taskOptions?.workOrderDisplayCode || '').trim().toUpperCase() || String(workOrderId);
const taskTitle = String(taskOptions?.taskTitle || '').trim()
.replace(/\s+/g, '_')
.replace(/[^A-Za-z0-9_-]+/g, '')
.replace(/^[_\-.]+|[_\-.]+$/g, '') || `task-${taskId}`;
saveBlobToFile(blob, `${workOrderDisplayCode}.SN-${taskTitle}.docx`);
showToast('DOCX servisnih zapisa za odabrani task je preuzet.', 'success');
} else {
saveBlobToFile(blob, `${workOrderId}.work-order-service-records.docx`);
@@ -1010,6 +1020,34 @@ export async function downloadMonthlyCostsReport(year, month) {
}
}
export async function downloadMonthlyServiceTasksArchive(year, month) {
try {
const blob = await api.get(
`fleet/reports/monthly-service-tasks-archive/?year=${year}&month=${month}`,
{ responseType: 'blob' },
);
saveBlobToFile(blob, `MT-${String(month).padStart(2, '0')}-${year}-SN.zip`);
showToast('ZIP pojedinačnih servisnih taskova je preuzet.', 'success');
} catch (err) {
showToast(err?.message || 'Preuzimanje ZIP-a servisnih taskova nije uspjelo.', 'error');
throw err;
}
}
export async function downloadMonthlyWorkOrdersArchive(year, month) {
try {
const blob = await api.get(
`fleet/reports/monthly-work-orders-archive/?year=${year}&month=${month}`,
{ responseType: 'blob' },
);
saveBlobToFile(blob, `MT-${String(month).padStart(2, '0')}-${year}-PN.zip`);
showToast('ZIP putnih naloga i računa je preuzet.', 'success');
} catch (err) {
showToast(err?.message || 'Preuzimanje ZIP-a putnih naloga nije uspjelo.', 'error');
throw err;
}
}
export async function downloadGeneratedPdfByUrl(downloadUrl, filename = 'document.pdf') {
if (!downloadUrl) {
showToast('Nedostaje URL za preuzimanje PDF-a.', 'error');