diff --git a/backend/src/main/java/com/printcalculator/controller/QuoteSessionController.java b/backend/src/main/java/com/printcalculator/controller/QuoteSessionController.java index ffeb59a..84f7bcd 100644 --- a/backend/src/main/java/com/printcalculator/controller/QuoteSessionController.java +++ b/backend/src/main/java/com/printcalculator/controller/QuoteSessionController.java @@ -142,7 +142,24 @@ public class QuoteSessionController { else if (settings.getMaterial().toLowerCase().contains("petg")) filamentProfile = "Generic PETG"; else if (settings.getMaterial().toLowerCase().contains("tpu")) filamentProfile = "Generic TPU"; else if (settings.getMaterial().toLowerCase().contains("abs")) filamentProfile = "Generic ABS"; + + // Update Session Material + session.setMaterialCode(settings.getMaterial()); + } else { + // Fallback if null? + session.setMaterialCode("pla_basic"); } + + // Update Session Settings for Persistence + if (settings.getNozzleDiameter() != null) session.setNozzleDiameterMm(BigDecimal.valueOf(settings.getNozzleDiameter())); + if (settings.getLayerHeight() != null) session.setLayerHeightMm(BigDecimal.valueOf(settings.getLayerHeight())); + if (settings.getInfillDensity() != null) session.setInfillPercent(settings.getInfillDensity().intValue()); + if (settings.getInfillPattern() != null) session.setInfillPattern(settings.getInfillPattern()); + if (settings.getSupportsEnabled() != null) session.setSupportsEnabled(settings.getSupportsEnabled()); + if (settings.getNotes() != null) session.setNotes(settings.getNotes()); + + // Save session updates + sessionRepo.save(session); String processProfile = "0.20mm Standard @BBL A1"; // Mapping quality to process @@ -155,19 +172,26 @@ public class QuoteSessionController { else if (settings.getLayerHeight() <= 0.12) processProfile = "0.12mm Fine @BBL A1"; } + // Build overrides map from settings // Build overrides map from settings Map processOverrides = new HashMap<>(); if (settings.getLayerHeight() != null) processOverrides.put("layer_height", String.valueOf(settings.getLayerHeight())); if (settings.getInfillDensity() != null) processOverrides.put("sparse_infill_density", settings.getInfillDensity() + "%"); if (settings.getInfillPattern() != null) processOverrides.put("sparse_infill_pattern", settings.getInfillPattern()); + if (Boolean.TRUE.equals(settings.getSupportsEnabled())) processOverrides.put("enable_support", "1"); + Map machineOverrides = new HashMap<>(); + if (settings.getNozzleDiameter() != null) { + machineOverrides.put("nozzle_diameter", String.valueOf(settings.getNozzleDiameter())); + } + // 3. Slice (Use persistent path) PrintStats stats = slicerService.slice( persistentPath.toFile(), machineProfile, filamentProfile, processProfile, - null, // machine overrides + machineOverrides, // machine overrides processOverrides ); @@ -227,17 +251,20 @@ public class QuoteSessionController { settings.setLayerHeight(0.28); settings.setInfillDensity(15.0); settings.setInfillPattern("grid"); + if (settings.getNozzleDiameter() == null) settings.setNozzleDiameter(0.4); break; case "high": settings.setLayerHeight(0.12); settings.setInfillDensity(20.0); settings.setInfillPattern("gyroid"); + if (settings.getNozzleDiameter() == null) settings.setNozzleDiameter(0.4); break; case "standard": default: settings.setLayerHeight(0.20); settings.setInfillDensity(20.0); settings.setInfillPattern("grid"); + if (settings.getNozzleDiameter() == null) settings.setNozzleDiameter(0.4); break; } } else { @@ -245,6 +272,8 @@ public class QuoteSessionController { if (settings.getLayerHeight() == null) settings.setLayerHeight(0.20); if (settings.getInfillDensity() == null) settings.setInfillDensity(20.0); if (settings.getInfillPattern() == null) settings.setInfillPattern("grid"); + if (settings.getNozzleDiameter() == null) settings.setNozzleDiameter(0.4); + if (settings.getSupportsEnabled() == null) settings.setSupportsEnabled(false); } } diff --git a/backend/src/main/java/com/printcalculator/dto/PrintSettingsDto.java b/backend/src/main/java/com/printcalculator/dto/PrintSettingsDto.java index c63565d..307fa15 100644 --- a/backend/src/main/java/com/printcalculator/dto/PrintSettingsDto.java +++ b/backend/src/main/java/com/printcalculator/dto/PrintSettingsDto.java @@ -19,5 +19,6 @@ public class PrintSettingsDto { private Double infillDensity; private String infillPattern; private Boolean supportsEnabled; + private Double nozzleDiameter; private String notes; } diff --git a/backend/src/test/java/com/printcalculator/ManualSessionPersistenceTest.java b/backend/src/test/java/com/printcalculator/ManualSessionPersistenceTest.java new file mode 100644 index 0000000..168fd5c --- /dev/null +++ b/backend/src/test/java/com/printcalculator/ManualSessionPersistenceTest.java @@ -0,0 +1,133 @@ +package com.printcalculator; + +import com.printcalculator.controller.QuoteSessionController; +import com.printcalculator.dto.PrintSettingsDto; +import com.printcalculator.entity.QuoteSession; +import com.printcalculator.entity.QuoteLineItem; +import com.printcalculator.repository.QuoteSessionRepository; +import com.printcalculator.repository.QuoteLineItemRepository; +import com.printcalculator.repository.PrinterMachineRepository; +import com.printcalculator.service.SlicerService; +import com.printcalculator.service.QuoteCalculator; +import com.printcalculator.service.StorageService; +import com.printcalculator.model.PrintStats; +import com.printcalculator.model.QuoteResult; +import com.printcalculator.entity.PrinterMachine; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.http.ResponseEntity; +import org.springframework.transaction.annotation.Transactional; + +import java.io.File; +import java.math.BigDecimal; +import java.nio.file.Path; +import java.util.Optional; +import java.util.Map; +import java.util.List; +import java.util.UUID; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; +import static org.junit.jupiter.api.Assertions.*; + +import org.mockito.ArgumentCaptor; + +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; + +@WebMvcTest(QuoteSessionController.class) +public class ManualSessionPersistenceTest { + + @Autowired + private QuoteSessionController controller; + + @MockBean + private QuoteSessionRepository sessionRepo; + + @MockBean + private QuoteLineItemRepository lineItemRepo; // Mock this too + + @MockBean + private SlicerService slicerService; + + @MockBean + private StorageService storageService; + + @MockBean + private QuoteCalculator quoteCalculator; + + @MockBean + private PrinterMachineRepository machineRepo; + + @MockBean + private com.printcalculator.repository.PricingPolicyRepository pricingRepo; // Add this if needed by controller + + @Test + public void testSettingsPersistence() throws Exception { + // Prepare + UUID sessionId = UUID.randomUUID(); + QuoteSession session = new QuoteSession(); + session.setId(sessionId); + session.setMaterialCode("pla_basic"); // Initial state + + when(sessionRepo.findById(sessionId)).thenReturn(Optional.of(session)); + when(sessionRepo.save(any(QuoteSession.class))).thenAnswer(i -> i.getArguments()[0]); + when(lineItemRepo.save(any(QuoteLineItem.class))).thenAnswer(i -> i.getArguments()[0]); + + // 2. Add Item with Custom Settings + PrintSettingsDto settings = new PrintSettingsDto(); + settings.setComplexityMode("ADVANCED"); + settings.setMaterial("petg_basic"); + settings.setLayerHeight(0.12); + settings.setInfillDensity(50.0); + settings.setInfillPattern("gyroid"); + settings.setSupportsEnabled(true); + settings.setNozzleDiameter(0.6); + settings.setNotes("Test Notes"); + + MockMultipartFile file = new MockMultipartFile("file", "test.stl", "application/octet-stream", "dummy content".getBytes()); + + // Mock dependencies + when(machineRepo.findFirstByIsActiveTrue()).thenReturn(Optional.of(new PrinterMachine(){{ + setPrinterDisplayName("TestPrinter"); + setSlicerMachineProfile("TestProfile"); + }})); + when(slicerService.slice(any(), any(), any(), any(), any(), any())).thenReturn(new PrintStats(100, "1m", 10.0, 100)); + when(quoteCalculator.calculate(any(), any(), any())).thenReturn( + new QuoteResult(10.0, "CHF", new PrintStats(100, "1m", 10.0, 100), 0.0) + ); + when(storageService.loadAsResource(any())).thenReturn(new org.springframework.core.io.ByteArrayResource("dummy".getBytes()){ + @Override + public File getFile() { return new File("dummy"); } + }); + + controller.addItemToExistingSession(sessionId, settings, file); + + // 3. Verify Session Updated via Save Call capture + ArgumentCaptor captor = ArgumentCaptor.forClass(QuoteSession.class); + verify(sessionRepo).save(captor.capture()); + + QuoteSession updatedSession = captor.getValue(); + + assertEquals("petg_basic", updatedSession.getMaterialCode()); + assertEquals(0, BigDecimal.valueOf(0.12).compareTo(updatedSession.getLayerHeightMm())); + assertEquals(50, updatedSession.getInfillPercent()); + assertEquals("gyroid", updatedSession.getInfillPattern()); + assertTrue(updatedSession.getSupportsEnabled()); + assertEquals(0, BigDecimal.valueOf(0.6).compareTo(updatedSession.getNozzleDiameterMm())); + assertEquals("Test Notes", updatedSession.getNotes()); + + System.out.println("Verification Passed: Settings were persisted to Session."); + } + @org.springframework.boot.test.context.TestConfiguration + static class TestConfig { + @org.springframework.context.annotation.Bean + public org.springframework.transaction.PlatformTransactionManager transactionManager() { + return org.mockito.Mockito.mock(org.springframework.transaction.PlatformTransactionManager.class); + } + } +}