dev #10
@@ -2,12 +2,12 @@ package com.printcalculator;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
@SpringBootApplication
|
||||
@SpringBootApplication(exclude = {UserDetailsServiceAutoConfiguration.class})
|
||||
@EnableTransactionManagement
|
||||
@EnableScheduling
|
||||
@EnableAsync
|
||||
|
||||
@@ -29,6 +29,8 @@ public class SecurityConfig {
|
||||
.logout(AbstractHttpConfigurer::disable)
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
|
||||
.requestMatchers("/actuator/health", "/actuator/health/**").permitAll()
|
||||
.requestMatchers("/actuator/**").denyAll()
|
||||
.requestMatchers("/api/admin/auth/login").permitAll()
|
||||
.requestMatchers("/api/admin/**").authenticated()
|
||||
.anyRequest().permitAll()
|
||||
|
||||
@@ -97,7 +97,7 @@ public class QuoteSessionController {
|
||||
session.setExpiresAt(OffsetDateTime.now().plusDays(30));
|
||||
|
||||
var policy = pricingRepo.findFirstByIsActiveTrueOrderByValidFromDesc();
|
||||
session.setSetupCostChf(policy != null ? policy.getFixedJobFeeChf() : BigDecimal.ZERO);
|
||||
session.setSetupCostChf(quoteCalculator.calculateSessionSetupFee(policy));
|
||||
|
||||
session = sessionRepo.save(session);
|
||||
return ResponseEntity.ok(session);
|
||||
|
||||
@@ -21,6 +21,8 @@ import java.util.List;
|
||||
|
||||
@Service
|
||||
public class QuoteCalculator {
|
||||
private static final BigDecimal SETUP_FEE_DOUBLE_THRESHOLD_CHF = BigDecimal.TEN;
|
||||
private static final BigDecimal SETUP_FEE_MULTIPLIER_BELOW_THRESHOLD = BigDecimal.valueOf(2);
|
||||
|
||||
private final PricingPolicyRepository pricingRepo;
|
||||
private final PricingPolicyMachineHourTierRepository tierRepo;
|
||||
@@ -111,6 +113,21 @@ public class QuoteCalculator {
|
||||
return rawCost.multiply(markupFactor).setScale(2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
public BigDecimal calculateSessionSetupFee(PricingPolicy policy) {
|
||||
if (policy == null || policy.getFixedJobFeeChf() == null) {
|
||||
return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
BigDecimal baseSetupFee = policy.getFixedJobFeeChf();
|
||||
if (baseSetupFee.compareTo(SETUP_FEE_DOUBLE_THRESHOLD_CHF) < 0) {
|
||||
return baseSetupFee
|
||||
.multiply(SETUP_FEE_MULTIPLIER_BELOW_THRESHOLD)
|
||||
.setScale(2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
return baseSetupFee.setScale(2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
private BigDecimal calculateMachineCost(PricingPolicy policy, BigDecimal hours) {
|
||||
List<PricingPolicyMachineHourTier> tiers = tierRepo.findAllByPricingPolicyOrderByTierStartHoursAsc(policy);
|
||||
if (tiers.isEmpty()) {
|
||||
|
||||
@@ -7,6 +7,7 @@ spring.datasource.username=${DB_USERNAME:printcalc}
|
||||
spring.datasource.password=${DB_PASSWORD:printcalc_secret}
|
||||
spring.jpa.hibernate.ddl-auto=update
|
||||
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
|
||||
spring.jpa.open-in-view=false
|
||||
|
||||
|
||||
# Slicer Configuration
|
||||
@@ -47,3 +48,6 @@ admin.password=${ADMIN_PASSWORD}
|
||||
admin.session.secret=${ADMIN_SESSION_SECRET}
|
||||
admin.session.ttl-minutes=${ADMIN_SESSION_TTL_MINUTES:480}
|
||||
admin.auth.trust-proxy-headers=${ADMIN_AUTH_TRUST_PROXY_HEADERS:false}
|
||||
|
||||
# Expose only liveness endpoint by default.
|
||||
management.endpoints.web.exposure.include=health
|
||||
|
||||
@@ -133,6 +133,8 @@
|
||||
"TITLE": "Über uns",
|
||||
"EYEBROW": "3D-Druck-Labor",
|
||||
"SUBTITLE": "Wir sind zwei Studenten mit viel Motivation und Lernbereitschaft.",
|
||||
"HOW_TEXT": "3D Fab ist entstanden, um das Potenzial des 3D-Drucks in alltagstaugliche Lösungen zu verwandeln. Wir haben mit technischer Neugier begonnen und sind zur Herstellung von Ersatzteilen, Produkten und maßgeschneiderten Prototypen gekommen. Um von einer Idee zu einem konkreten Projekt zu gelangen, haben wir unseren automatischen Rechner eingeführt: klare Angebote in einem Klick, damit Sie einen professionellen Service ohne Preisüberraschungen erhalten.",
|
||||
"PASSIONS_TITLE": "Unsere Interessen",
|
||||
"PASSION_BIKE_TRIAL": "Bike Trial",
|
||||
"PASSION_MOUNTAIN": "Berge",
|
||||
"PASSION_SKI": "Ski",
|
||||
|
||||
@@ -133,6 +133,8 @@
|
||||
"TITLE": "About Us",
|
||||
"EYEBROW": "3D Printing Lab",
|
||||
"SUBTITLE": "We are two students with a strong desire to build and learn.",
|
||||
"HOW_TEXT": "3D Fab was created to turn the potential of 3D printing into everyday solutions. We started from technical curiosity and grew into producing spare parts, products, and custom prototypes. To move from an idea to a concrete project, we launched our automatic calculator: clear quotes in one click, so you get a professional service with no price surprises.",
|
||||
"PASSIONS_TITLE": "Our interests",
|
||||
"PASSION_BIKE_TRIAL": "Bike trial",
|
||||
"PASSION_MOUNTAIN": "Mountain",
|
||||
"PASSION_SKI": "Ski",
|
||||
|
||||
@@ -190,6 +190,8 @@
|
||||
"TITLE": "Qui sommes-nous",
|
||||
"EYEBROW": "Atelier d'impression 3D",
|
||||
"SUBTITLE": "Nous sommes deux étudiants avec beaucoup d'envie de faire et d'apprendre.",
|
||||
"HOW_TEXT": "3D Fab est né pour transformer le potentiel de l'impression 3D en solutions du quotidien. Nous sommes partis de la curiosité technique et nous sommes arrivés à la production de pièces de rechange, de produits et de prototypes sur mesure. Pour passer d'une idée à un projet concret, nous avons lancé notre calculateur automatique : des devis clairs en un clic pour vous garantir un service professionnel, sans surprises sur le prix.",
|
||||
"PASSIONS_TITLE": "Nos centres d'intérêt",
|
||||
"PASSION_BIKE_TRIAL": "Bike trial",
|
||||
"PASSION_MOUNTAIN": "Montagne",
|
||||
"PASSION_SKI": "Ski",
|
||||
|
||||
Reference in New Issue
Block a user