From bb276b6504fa5ed8aba12042ac5d52dd9929fbb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joe=20K=C3=BCng?= Date: Mon, 16 Feb 2026 13:57:44 +0100 Subject: [PATCH] fix(back-end): fix exclude object 0 --- backend/build.gradle | 1 + .../service/InvoicePdfRenderingService.java | 2 + .../src/main/resources/templates/invoice.html | 6 +- .../services/quote-estimator.service.ts | 79 ++++++++++--------- 4 files changed, 49 insertions(+), 39 deletions(-) diff --git a/backend/build.gradle b/backend/build.gradle index abd1641..b15d8ef 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -34,6 +34,7 @@ dependencies { compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' implementation 'io.github.openhtmltopdf:openhtmltopdf-pdfbox:1.1.37' + implementation 'io.github.openhtmltopdf:openhtmltopdf-svg-support:1.1.37' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'net.codecrete.qrbill:qrbill-generator:3.4.0' diff --git a/backend/src/main/java/com/printcalculator/service/InvoicePdfRenderingService.java b/backend/src/main/java/com/printcalculator/service/InvoicePdfRenderingService.java index de1faaa..a21e59f 100644 --- a/backend/src/main/java/com/printcalculator/service/InvoicePdfRenderingService.java +++ b/backend/src/main/java/com/printcalculator/service/InvoicePdfRenderingService.java @@ -1,6 +1,7 @@ package com.printcalculator.service; import com.openhtmltopdf.pdfboxout.PdfRendererBuilder; +import com.openhtmltopdf.svgsupport.BatikSVGDrawer; import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Service; import org.thymeleaf.TemplateEngine; @@ -34,6 +35,7 @@ public class InvoicePdfRenderingService { PdfRendererBuilder openHtmlToPdfRendererBuilder = new PdfRendererBuilder(); openHtmlToPdfRendererBuilder.useFastMode(); + openHtmlToPdfRendererBuilder.useSVGDrawer(new BatikSVGDrawer()); openHtmlToPdfRendererBuilder.withHtmlContent(renderedInvoiceHtml, classpathBaseUrlForHtmlResources); openHtmlToPdfRendererBuilder.toStream(generatedPdfByteArrayOutputStream); openHtmlToPdfRendererBuilder.run(); diff --git a/backend/src/main/resources/templates/invoice.html b/backend/src/main/resources/templates/invoice.html index b9464c8..8584971 100644 --- a/backend/src/main/resources/templates/invoice.html +++ b/backend/src/main/resources/templates/invoice.html @@ -76,9 +76,9 @@ Pagamento entro 7 giorni. Grazie. - -
-
+
+
+
diff --git a/frontend/src/app/features/calculator/services/quote-estimator.service.ts b/frontend/src/app/features/calculator/services/quote-estimator.service.ts index 93a5f80..12e1777 100644 --- a/frontend/src/app/features/calculator/services/quote-estimator.service.ts +++ b/frontend/src/app/features/calculator/services/quote-estimator.service.ts @@ -180,26 +180,24 @@ export class QuoteEstimatorService { const sessionId = sessionRes.id; const sessionSetupCost = sessionRes.setupCostChf || 0; - // 2. Upload files to this session + // 2. Process items SEQUENTIALLY to avoid timeouts/overload const totalItems = request.items.length; const allProgress: number[] = new Array(totalItems).fill(0); const finalResponses: any[] = []; - let completedRequests = 0; + let completedCount = 0; - const checkCompletion = () => { - const avg = Math.round(allProgress.reduce((a, b) => a + b, 0) / totalItems); - observer.next(avg); - - if (completedRequests === totalItems) { - finalize(finalResponses, sessionSetupCost, sessionId); - } - }; + const processNextItem = (index: number) => { + if (index >= totalItems) { + // All done + finalize(finalResponses, sessionSetupCost, sessionId); + return; + } - request.items.forEach((item, index) => { - const formData = new FormData(); - formData.append('file', item.file); - - const settings = { + const item = request.items[index]; + const formData = new FormData(); + formData.append('file', item.file); + + const settings = { complexityMode: request.mode.toUpperCase(), material: this.mapMaterial(request.material), quality: request.quality, @@ -209,36 +207,48 @@ export class QuoteEstimatorService { infillDensity: request.mode === 'advanced' ? request.infillDensity : null, infillPattern: request.mode === 'advanced' ? request.infillPattern : null, nozzleDiameter: request.mode === 'advanced' ? request.nozzleDiameter : null - }; - - const settingsBlob = new Blob([JSON.stringify(settings)], { type: 'application/json' }); - formData.append('settings', settingsBlob); + }; - this.http.post(`${environment.apiUrl}/api/quote-sessions/${sessionId}/line-items`, formData, { - headers, - reportProgress: true, - observe: 'events' - }).subscribe({ + const settingsBlob = new Blob([JSON.stringify(settings)], { type: 'application/json' }); + formData.append('settings', settingsBlob); + + this.http.post(`${environment.apiUrl}/api/quote-sessions/${sessionId}/line-items`, formData, { + headers, + reportProgress: true, + observe: 'events' + }).subscribe({ next: (event) => { if (event.type === HttpEventType.UploadProgress && event.total) { allProgress[index] = Math.round((100 * event.loaded) / event.total); - checkCompletion(); + reportProgress(); } else if (event.type === HttpEventType.Response) { - allProgress[index] = 100; - finalResponses[index] = { ...event.body, success: true, fileName: item.file.name, originalQty: item.quantity, originalItem: item }; - completedRequests++; - checkCompletion(); + allProgress[index] = 100; + finalResponses[index] = { ...event.body, success: true, fileName: item.file.name, originalQty: item.quantity, originalItem: item }; + completedCount++; + reportProgress(); + // Next + processNextItem(index + 1); } }, error: (err) => { console.error('Item upload failed', err); const errorMsg = err.error?.code === 'VIRUS_DETECTED' ? 'VIRUS_DETECTED' : 'UPLOAD_FAILED'; finalResponses[index] = { success: false, fileName: item.file.name, error: errorMsg }; - completedRequests++; - checkCompletion(); + completedCount++; + reportProgress(); + // Next even if error + processNextItem(index + 1); } }); - }); + }; + + const reportProgress = () => { + const avg = Math.round(allProgress.reduce((a, b) => a + b, 0) / totalItems); + observer.next(avg); + }; + + // Start first item + processNextItem(0); }, error: (err) => { console.error('Failed to create session', err); @@ -268,10 +278,8 @@ export class QuoteEstimatorService { unitTime: res.printTimeSeconds || 0, unitWeight: res.materialGrams || 0, quantity: quantity, - material: request.material, + material: this.mapMaterial(request.material), // Uses session material color: res.originalItem.color || 'Default' - // Store ID if needed for updates? QuoteItem interface might need update - // or we map it in component }); grandTotal += unitPrice * quantity; @@ -280,7 +288,6 @@ export class QuoteEstimatorService { }); if (validCount === 0) { - // Check if any failed due to virus const virusError = responses.find(r => r.error === 'VIRUS_DETECTED'); if (virusError) { observer.error('VIRUS_DETECTED');