diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..751abe9 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,25 @@ +version: '3.8' + +services: + imprimelibros-db: + image: mysql:8.0 + container_name: imprimelibros-db + restart: unless-stopped + environment: + MYSQL_ROOT_PASSWORD: NrXz6DK6UoN + MYSQL_DATABASE: imprimelibros + MYSQL_USER: imprimelibros_user + MYSQL_PASSWORD: om91irrDctd + ports: + - "3306:3306" + volumes: + - db_data:/var/lib/mysql + networks: + - imprimelibros-network + +volumes: + db_data: + +networks: + imprimelibros-network: + driver: bridge diff --git a/pom.xml b/pom.xml index 3c5cb5b..9e40c4e 100644 --- a/pom.xml +++ b/pom.xml @@ -39,6 +39,10 @@ org.springframework.boot spring-boot-starter-thymeleaf + + org.springframework.boot + spring-boot-starter-validation + nz.net.ultraq.thymeleaf thymeleaf-layout-dialect @@ -47,18 +51,25 @@ org.springframework.boot spring-boot-starter-web + + jakarta.validation + jakarta.validation-api + + + com.fasterxml.jackson.core + jackson-databind + org.thymeleaf.extras thymeleaf-extras-springsecurity6 - org.springframework.boot spring-boot-devtools runtime true - + org.springframework.boot spring-boot-starter-test diff --git a/src/main/java/com/imprimelibros/erp/config/SecurityConfig.java b/src/main/java/com/imprimelibros/erp/config/SecurityConfig.java index e678349..b3fb0d8 100644 --- a/src/main/java/com/imprimelibros/erp/config/SecurityConfig.java +++ b/src/main/java/com/imprimelibros/erp/config/SecurityConfig.java @@ -4,6 +4,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; @Configuration public class SecurityConfig { @@ -11,15 +12,24 @@ public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http - .authorizeHttpRequests(auth -> auth - .requestMatchers("/", "/assets/**", "/css/**", "/js/**", "/images/**", "/public/**").permitAll() - .anyRequest().authenticated() - ) - .formLogin(login -> login - //.loginPage("/login") añadir cuando se tenga login personalizado - .permitAll() - ) - .logout(logout -> logout.permitAll()); + .authorizeHttpRequests(auth -> auth + .requestMatchers( + "/", + "/assets/**", + "/css/**", + "/js/**", + "/images/**", + "/public/**", + "/error", + "/presupuesto/validar/**") + .permitAll() + .anyRequest().authenticated()) + .csrf(csrf -> csrf + .ignoringRequestMatchers("/presupuesto/validar/**")) + .formLogin(login -> login + // .loginPage("/login") añadir cuando se tenga login personalizado + .permitAll()) + .logout(logout -> logout.permitAll()); return http.build(); } diff --git a/src/main/java/com/imprimelibros/erp/config/validation/ConsistentTiradas.java b/src/main/java/com/imprimelibros/erp/config/validation/ConsistentTiradas.java new file mode 100644 index 0000000..67009d3 --- /dev/null +++ b/src/main/java/com/imprimelibros/erp/config/validation/ConsistentTiradas.java @@ -0,0 +1,16 @@ +package com.imprimelibros.erp.config.validation; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; + +import java.lang.annotation.*; + +@Documented +@Constraint(validatedBy = ConsistentTiradasValidator.class) +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ConsistentTiradas { + String message() default "Las tiradas deben ser todas mayores o todas menores al valor POD"; + Class[] groups() default {}; + Class[] payload() default {}; +} diff --git a/src/main/java/com/imprimelibros/erp/config/validation/ConsistentTiradasValidator.java b/src/main/java/com/imprimelibros/erp/config/validation/ConsistentTiradasValidator.java new file mode 100644 index 0000000..7224a1c --- /dev/null +++ b/src/main/java/com/imprimelibros/erp/config/validation/ConsistentTiradasValidator.java @@ -0,0 +1,52 @@ +package com.imprimelibros.erp.config.validation; + +import com.imprimelibros.erp.entity.Presupuesto; +import com.imprimelibros.erp.service.VariableService; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.MessageSource; +import org.springframework.context.i18n.LocaleContextHolder; + +public class ConsistentTiradasValidator implements ConstraintValidator { + + @Autowired + private VariableService variableService; + @Autowired + private MessageSource messageSource; + + @Override + public boolean isValid(Presupuesto presupuesto, ConstraintValidatorContext context) { + if (presupuesto == null) + return true; + + Integer[] tiradas = presupuesto.getTiradas(); + Integer podValue = variableService.getValorEntero("POD"); + + boolean allAbove = true; + boolean allBelow = true; + + for (Integer t : tiradas) { + if (t == null) + continue; + if (t <= podValue) + allAbove = false; + if (t >= podValue) + allBelow = false; + } + + if (!(allAbove || allBelow)) { + + String mensajeInterpolado = messageSource.getMessage( + "presupuesto.errores.tiradas.consistentes", // clave del mensaje + new Object[] { podValue }, // parámetros para {0} + LocaleContextHolder.getLocale() // respeta el idioma actual + ); + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate(mensajeInterpolado) + .addConstraintViolation(); + return false; + } + return true; + } +} diff --git a/src/main/java/com/imprimelibros/erp/config/validation/Par.java b/src/main/java/com/imprimelibros/erp/config/validation/Par.java new file mode 100644 index 0000000..7ce1400 --- /dev/null +++ b/src/main/java/com/imprimelibros/erp/config/validation/Par.java @@ -0,0 +1,16 @@ +package com.imprimelibros.erp.config.validation; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; + +import java.lang.annotation.*; + +@Documented +@Constraint(validatedBy = ParValidator.class) +@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER }) +@Retention(RetentionPolicy.RUNTIME) +public @interface Par { + String message() default "El valor debe ser un número par"; + Class[] groups() default {}; + Class[] payload() default {}; +} diff --git a/src/main/java/com/imprimelibros/erp/config/validation/ParValidator.java b/src/main/java/com/imprimelibros/erp/config/validation/ParValidator.java new file mode 100644 index 0000000..84b722e --- /dev/null +++ b/src/main/java/com/imprimelibros/erp/config/validation/ParValidator.java @@ -0,0 +1,14 @@ +package com.imprimelibros.erp.config.validation; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; + +public class ParValidator implements ConstraintValidator { + + @Override + public boolean isValid(Integer value, ConstraintValidatorContext context) { + if (value == null) return true; // se permite null, usa @NotNull aparte si lo necesitas + return value % 2 == 0; + } +} + diff --git a/src/main/java/com/imprimelibros/erp/config/validation/PresupuestoValidationGroups.java b/src/main/java/com/imprimelibros/erp/config/validation/PresupuestoValidationGroups.java new file mode 100644 index 0000000..75c6be1 --- /dev/null +++ b/src/main/java/com/imprimelibros/erp/config/validation/PresupuestoValidationGroups.java @@ -0,0 +1,9 @@ +package com.imprimelibros.erp.config.validation; + +public class PresupuestoValidationGroups { + + public interface DatosGenerales {} + public interface Interior {} + public interface Cubierta {} + +} diff --git a/src/main/java/com/imprimelibros/erp/controller/HomeController.java b/src/main/java/com/imprimelibros/erp/controller/HomeController.java index 9d4a9e1..92d57e0 100644 --- a/src/main/java/com/imprimelibros/erp/controller/HomeController.java +++ b/src/main/java/com/imprimelibros/erp/controller/HomeController.java @@ -1,24 +1,46 @@ package com.imprimelibros.erp.controller; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.MessageSource; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; +import com.imprimelibros.erp.i18n.TranslationService; +import com.imprimelibros.erp.service.VariableService; + +import org.springframework.security.authentication.AnonymousAuthenticationToken; +import org.springframework.security.core.Authentication; + +import java.util.List; import java.util.Locale; +import java.util.Map; @Controller public class HomeController { @Autowired - private MessageSource messageSource; + private TranslationService translationService; + @Autowired + private VariableService variableService; @GetMapping("/") - public String index(Model model, Locale locale) { - //model.addAttribute("title", messageSource.getMessage("t-home", null, locale)); - model.addAttribute("title", "Inicio"); - return "imprimelibros/home"; + public String index(Model model, Authentication authentication, Locale locale) { + + boolean isAuthenticated = authentication != null && authentication.isAuthenticated() + && !(authentication instanceof AnonymousAuthenticationToken); + + if (!isAuthenticated) { + + List keys = List.of( + "presupuesto.plantilla-cubierta", + "presupuesto.plantilla-cubierta-text", + "presupuesto.impresion-cubierta", + "presupuesto.impresion-cubierta-help"); + + Map translations = translationService.getTranslations(locale, keys); + model.addAttribute("languageBundle", translations); + model.addAttribute("pod", variableService.getValorEntero("POD")); + } + return "imprimelibros/home"; } } - diff --git a/src/main/java/com/imprimelibros/erp/controller/PresupuestoController.java b/src/main/java/com/imprimelibros/erp/controller/PresupuestoController.java new file mode 100644 index 0000000..4e5ccc7 --- /dev/null +++ b/src/main/java/com/imprimelibros/erp/controller/PresupuestoController.java @@ -0,0 +1,53 @@ +package com.imprimelibros.erp.controller; + +import org.springframework.web.bind.annotation.RestController; + +import com.imprimelibros.erp.service.PresupuestoService; + +import java.util.HashMap; + +import org.springframework.beans.factory.annotation.Autowired; + +import org.springframework.http.ResponseEntity; +import org.springframework.validation.BindingResult; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.PostMapping; + +import jakarta.validation.Valid; // o javax.validation.Valid según tu versión + +import java.util.Map; + +import com.imprimelibros.erp.config.validation.PresupuestoValidationGroups; +import com.imprimelibros.erp.entity.Presupuesto; + +@RestController +@RequestMapping("/presupuesto") +public class PresupuestoController { + + @Autowired + protected PresupuestoService presupuestoService; + + @PostMapping("/validar/datos-generales") + public ResponseEntity validarDatosGenerales( + @Validated(PresupuestoValidationGroups.DatosGenerales.class) Presupuesto presupuesto, + BindingResult result) { + + Map errores = new HashMap<>(); + + // errores de campos individuales + result.getFieldErrors().forEach(error -> errores.put(error.getField(), error.getDefaultMessage())); + + // errores globales (como tu @ConsistentTiradas) + result.getGlobalErrors().forEach(error -> errores.put("global", error.getDefaultMessage())); + + if (!errores.isEmpty()) { + return ResponseEntity.badRequest().body(errores); + } + + return ResponseEntity.ok().build(); + } + +} diff --git a/src/main/java/com/imprimelibros/erp/entity/Presupuesto.java b/src/main/java/com/imprimelibros/erp/entity/Presupuesto.java new file mode 100644 index 0000000..933438c --- /dev/null +++ b/src/main/java/com/imprimelibros/erp/entity/Presupuesto.java @@ -0,0 +1,153 @@ +package com.imprimelibros.erp.entity; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.persistence.*; + +import com.imprimelibros.erp.config.validation.PresupuestoValidationGroups; +import com.imprimelibros.erp.config.validation.ConsistentTiradas; +import com.imprimelibros.erp.config.validation.Par; + + +@ConsistentTiradas(groups = PresupuestoValidationGroups.DatosGenerales.class) +@Entity +@Table(name = "presupuesto") +public class Presupuesto { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + // Otros campos del presupuesto + @NotBlank(message = "{presupuesto.errores.titulo}", groups = PresupuestoValidationGroups.DatosGenerales.class) + @Column(name = "titulo") + private String titulo; + + @Column(name = "autor") + private String autor; + + @Column(name = "isbn") + private String isbn; + + @NotNull(message = "{presupuesto.errores.tirada1}", groups = PresupuestoValidationGroups.DatosGenerales.class) + @Column(name = "tirada1") + private Integer tirada1; + + @Column(name = "tirada2") + private Integer tirada2; + + @Column(name = "tirada3") + private Integer tirada3; + + @Column(name = "tirada4") + private Integer tirada4; + + @Par(message = "{presupuesto.errores.paginasNegro.par}", groups = PresupuestoValidationGroups.DatosGenerales.class) + @NotNull(message = "{presupuesto.errores.paginasNegro.required}", groups = PresupuestoValidationGroups.DatosGenerales.class) + @Column(name = "paginas_negro") + private Integer paginasNegro; + + @Par(message = "{presupuesto.errores.paginasColor.par}", groups = PresupuestoValidationGroups.DatosGenerales.class) + @NotNull(message = "{presupuesto.errores.paginasColor.required}", groups = PresupuestoValidationGroups.DatosGenerales.class) + @Column(name = "paginas_color") + private Integer paginasColor; + + @NotNull(message = "El papel interior no puede estar vacío", groups = PresupuestoValidationGroups.Interior.class) + @Column(name = "papel_interior") + private Integer papelInterior; + + + // Getters y Setters + + public String getAutor() { + return autor; + } + + public void setAutor(String autor) { + this.autor = autor; + } + + public String getIsbn() { + return isbn; + } + + public void setIsbn(String isbn) { + this.isbn = isbn; + } + + public Integer getTirada1() { + return tirada1; + } + + public void setTirada1(Integer tirada1) { + this.tirada1 = tirada1; + } + + public Integer getTirada2() { + return tirada2; + } + + public void setTirada2(Integer tirada2) { + this.tirada2 = tirada2; + } + + public Integer getTirada3() { + return tirada3; + } + + public void setTirada3(Integer tirada3) { + this.tirada3 = tirada3; + } + + public Integer getTirada4() { + return tirada4; + } + + public Integer[] getTiradas() { + return new Integer[]{tirada1, tirada2, tirada3, tirada4}; + } + + public void setTirada4(Integer tirada4) { + this.tirada4 = tirada4; + } + + public String getTitulo() { + return titulo; + } + + public void setTitulo(String titulo) { + this.titulo = titulo; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getPaginasNegro() { + return paginasNegro; + } + + public void setPaginasNegro(Integer paginasNegro) { + this.paginasNegro = paginasNegro; + } + + public Integer getPaginasColor() { + return paginasColor; + } + + public void setPaginasColor(Integer paginasColor) { + this.paginasColor = paginasColor; + } + + public Integer getPapelInterior() { + return papelInterior; + } + + public void setPapelInterior(Integer papelInterior) { + this.papelInterior = papelInterior; + } +} diff --git a/src/main/java/com/imprimelibros/erp/entity/Variable.java b/src/main/java/com/imprimelibros/erp/entity/Variable.java new file mode 100644 index 0000000..7c908ce --- /dev/null +++ b/src/main/java/com/imprimelibros/erp/entity/Variable.java @@ -0,0 +1,30 @@ +package com.imprimelibros.erp.entity; + +import jakarta.persistence.*; + +@Entity +@Table(name = "variables") +public class Variable { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String clave; + + private String valor; + + // Getters y setters + + public Long getId() { return id; } + + public void setId(Long id) { this.id = id; } + + public String getClave() { return clave; } + + public void setClave(String clave) { this.clave = clave; } + + public String getValor() { return valor; } + + public void setValor(String valor) { this.valor = valor; } +} diff --git a/src/main/java/com/imprimelibros/erp/i18n/TranslationService.java b/src/main/java/com/imprimelibros/erp/i18n/TranslationService.java new file mode 100644 index 0000000..65f2cc6 --- /dev/null +++ b/src/main/java/com/imprimelibros/erp/i18n/TranslationService.java @@ -0,0 +1,22 @@ +package com.imprimelibros.erp.i18n; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.MessageSource; +import org.springframework.stereotype.Component; + +import java.util.*; + +@Component +public class TranslationService { + + @Autowired + private MessageSource messageSource; + + public Map getTranslations(Locale locale, List keys) { + Map translations = new HashMap<>(); + for (String key : keys) { + translations.put(key, messageSource.getMessage(key, null, locale)); + } + return translations; + } +} diff --git a/src/main/java/com/imprimelibros/erp/repository/VariableRepository.java b/src/main/java/com/imprimelibros/erp/repository/VariableRepository.java new file mode 100644 index 0000000..141642d --- /dev/null +++ b/src/main/java/com/imprimelibros/erp/repository/VariableRepository.java @@ -0,0 +1,10 @@ +package com.imprimelibros.erp.repository; + +import com.imprimelibros.erp.entity.Variable; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface VariableRepository extends JpaRepository { + Optional findByClave(String clave); +} diff --git a/src/main/java/com/imprimelibros/erp/service/PresupuestoService.java b/src/main/java/com/imprimelibros/erp/service/PresupuestoService.java new file mode 100644 index 0000000..5e42aed --- /dev/null +++ b/src/main/java/com/imprimelibros/erp/service/PresupuestoService.java @@ -0,0 +1,18 @@ +package com.imprimelibros.erp.service; + +import org.springframework.stereotype.Service; + +@Service +public class PresupuestoService { + + public boolean validateDatosGenerales(int[] tiradas) { + // Implement the logic to validate the tiradas + // For example, check if all tiradas are positive integers + for (int tirada : tiradas) { + if (tirada <= 0) { + return false; // Invalid tirada found + } + } + return true; // All tiradas are valid + } +} diff --git a/src/main/java/com/imprimelibros/erp/service/VariableService.java b/src/main/java/com/imprimelibros/erp/service/VariableService.java new file mode 100644 index 0000000..255fe1c --- /dev/null +++ b/src/main/java/com/imprimelibros/erp/service/VariableService.java @@ -0,0 +1,20 @@ +package com.imprimelibros.erp.service; + +import com.imprimelibros.erp.repository.VariableRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class VariableService { + + @Autowired + private VariableRepository variableRepository; + + public Integer getValorEntero(String clave) { + return variableRepository.findByClave(clave) + .map(v -> Integer.parseInt(v.getValor())) + .orElseThrow( + () -> new IllegalArgumentException("No se encontró la variable con clave '" + clave + "'")); + } + +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 34b0f12..4addc83 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,2 +1,13 @@ spring.application.name=erp logging.level.org.springframework.security=DEBUG + +logging.level.root=WARN +logging.level.org.springframework=ERROR + +spring.datasource.url=jdbc:mysql://localhost:3306/imprimelibros +spring.datasource.username=imprimelibros_user +spring.datasource.password=om91irrDctd +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver + +spring.jpa.hibernate.ddl-auto=update +spring.jpa.show-sql=true \ No newline at end of file diff --git a/src/main/resources/i18n/presupuesto_es.properties b/src/main/resources/i18n/presupuesto_es.properties index 321b178..83d2430 100644 --- a/src/main/resources/i18n/presupuesto_es.properties +++ b/src/main/resources/i18n/presupuesto_es.properties @@ -1,7 +1,7 @@ presupuesto.datos-generales=Datos Generales presupuesto.interior=Interior presupuesto.cubierta=Cubierta -presupuesto.envio=Envío +presupuesto.extras=Extras # Pestaña datos generales de presupuesto presupuesto.informacion-libro=Información del libro @@ -13,7 +13,7 @@ presupuesto.tirada1=Tirada 1* presupuesto.tirada2=Tirada 2 presupuesto.tirada3=Tirada 3 presupuesto.tirada4=Tirada 4 -presupuesto.tiradasPODnoPOD=No puede mezclar tiradas menores de 30 unidades con mayores de 30 unidades +presupuesto.tiradasPODnoPOD=No puede mezclar tiradas menores de {0} unidades con mayores de {0} unidades presupuesto.formato=Formato presupuesto.orientacion.vertical=Vertical presupuesto.orientacion.apaisado=Apaisado @@ -26,5 +26,70 @@ presupuesto.paginas-negro=Páginas Negro presupuesto.paginas-color=Páginas Color presupuesto.siempre-pares=Siempre deben ser pares presupuesto.encuadernacion=Encuadernación +presupuesto.fresado-descripcion=Fresado (a partir de 32 páginas) +presupuesto.cosido-descripcion=Cosido (a partir de 32 páginas) +presupuesto.grapado-descripcion=Grapado (entre 12 y 40 páginas) +presupuesto.espiral-descripcion=Espiral (a partir de 20 páginas) +presupuesto.wire-o-descripcion=Wire-O (a partir de 20 páginas) presupuesto.encuadernacion-descripcion=Seleccione la encuadernación del libro -presupuesto.siguiente=Siguiente \ No newline at end of file +presupuesto.continuar-interior=Continuar a diseño interior + +# Pestaña interior de presupuesto +presupuesto.tipo-impresion=Tipo de impresión +presupuesto.tipo-impresion-descripcion=Seleccione entre calidad estándar o premium +presupuesto.papel-interior=Papel interior +presupuesto.papel-interior-descripcion=Seleccione el papel para el interior +presupuesto.gramaje-interior=Gramaje interior +presupuesto.gramaje-interior-descripcion=Seleccione el gramaje para el interior +presupuesto.blanco-negro=Blanco y negro +presupuesto.blanco-negro-premium= Blanco y negro Premium +presupuesto.color=Color +presupuesto.color-premium=Color Premium +presupuesto.offset-blanco=Offset Blanco +presupuesto.offset-ahuesado=Offset Ahuesado +presupuesto.offset-ahuesado-volumen=Offset Ahuesado Volumen +presupuesto.estucado-mate=Estucado Mate +presupuesto.volver-datos-generales=Volver a datos generales +presupuesto.continuar-cubierta=Continuar a diseño cubierta + +# Pestaña cubierta +presupuesto.plantilla-cubierta=Plantilla de cubierta +presupuesto.plantilla-cubierta-text=Recuerde que la cubierta es el conjunto formado por la portada, contraportada, lomo y solapas, en caso de que las lleve.


Si tiene dudas de las medidas puede solicitarnos una plantilla cuando haga el pedido. +presupuesto.tipo-cubierta=Tipo de cubierta +presupuesto.tipo-cubierta-descripcion=Seleccione el tipo de cubierta y sus opciones +presupuesto.tapa-blanda=Tapa blanda +presupuesto.tapa-dura=Tapa dura +presupuesto.tapa-dura-lomo-redondo=Tapa dura lomo redondo +presupuesto.sin-solapas=Sin solapas +presupuesto.con-solapas=Con solapas +presupuesto.impresion-cubierta=Impresión de cubierta +presupuesto.impresion-cubierta-help=La cubierta se puede imprimir por anverso y reverso, como en el caso de las revistas, pero para un libro normal con portada y contraportada, la impresión de cubierta es a una cara. +presupuesto.una-cara=Una cara +presupuesto.dos-caras=Dos caras +presupuesto.tamanio-solapa=Tamaño solapa +presupuesto.papel-guardas=Papel de guardas +presupuesto.guardas-impresas=Guardas impresas +presupuesto.no=No +presupuesto.cabezada=Cabezada +presupuesto.cabezada-blanca=Blanca +presupuesto.cabezada-verde=Verde +presupuesto.cabezada-azul=Azul +presupuesto.cabezada-roja-amarilla=Roja-Amarilla +presupuesto.papel-cubierta=Papel cubierta +presupuesto.papel-cubierta-descripcion=Seleccione el papel para la cubierta +presupuesto.cartulina-grafica-cubierta=Cartulina gráfica estucada a una cara +presupuesto.gramaje-cubierta=Gramaje cubierta +presupuesto.gramaje-cubierta-descripcion=Seleccione el gramaje para la cubierta +presupuesto.volver-interior=Volver a diseño interior +presupuesto.continuar-extras-libro=Continuar a extras del libro + + +# Errores +presupuesto.errores-title=Corrija los siguientes errores: +presupuesto.errores.titulo=El título es obligatorio +presupuesto.errores.tirada1=La tirada 1 es obligatoria +presupuesto.errores.tiradas.consistentes=Las tiradas deben ser consistentes (no mezclar tiradas menores de {0} unidades con mayores de {0} unidades) +presupuesto.errores.paginasNegro.required=El número de páginas en negro es obligatorio +presupuesto.errores.paginasNegro.par=El número de páginas en negro debe ser par +presupuesto.errores.paginasColor.required=El número de páginas en color es obligatorio +presupuesto.errores.paginasColor.par=El número de páginas en color debe ser par \ No newline at end of file diff --git a/src/main/resources/static/assets/css/presupuestador.css b/src/main/resources/static/assets/css/presupuestador.css index 051cc64..6f6c43e 100644 --- a/src/main/resources/static/assets/css/presupuestador.css +++ b/src/main/resources/static/assets/css/presupuestador.css @@ -18,6 +18,8 @@ border-radius: 8px; padding: 8px; + margin-inline: 5px; + transition: border 0.3s ease; } @@ -58,3 +60,14 @@ max-width: 100%; } } + +.gramaje-radio{ + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-width: 70px; /* Ancho mínimo */ + min-height: 70px; /* Alto mínimo */ + max-width: 70px; /* Ancho máximo */ + max-height: 70px; /* Alto máximo */ +} \ No newline at end of file diff --git a/src/main/resources/static/assets/images/imprimelibros/presupuestador/blancoYnegro.png b/src/main/resources/static/assets/images/imprimelibros/presupuestador/blancoYnegro.png new file mode 100644 index 0000000..459b3cb Binary files /dev/null and b/src/main/resources/static/assets/images/imprimelibros/presupuestador/blancoYnegro.png differ diff --git a/src/main/resources/static/assets/images/imprimelibros/presupuestador/cartulina-grafica.png b/src/main/resources/static/assets/images/imprimelibros/presupuestador/cartulina-grafica.png new file mode 100644 index 0000000..403b40d Binary files /dev/null and b/src/main/resources/static/assets/images/imprimelibros/presupuestador/cartulina-grafica.png differ diff --git a/src/main/resources/static/assets/images/imprimelibros/presupuestador/color.png b/src/main/resources/static/assets/images/imprimelibros/presupuestador/color.png new file mode 100644 index 0000000..cd80dd7 Binary files /dev/null and b/src/main/resources/static/assets/images/imprimelibros/presupuestador/color.png differ diff --git a/src/main/resources/static/assets/images/imprimelibros/presupuestador/colorFoto.png b/src/main/resources/static/assets/images/imprimelibros/presupuestador/colorFoto.png new file mode 100644 index 0000000..86f0573 Binary files /dev/null and b/src/main/resources/static/assets/images/imprimelibros/presupuestador/colorFoto.png differ diff --git a/src/main/resources/static/assets/images/imprimelibros/presupuestador/conSolapasCubierta.png b/src/main/resources/static/assets/images/imprimelibros/presupuestador/conSolapasCubierta.png new file mode 100644 index 0000000..6ad3d93 Binary files /dev/null and b/src/main/resources/static/assets/images/imprimelibros/presupuestador/conSolapasCubierta.png differ diff --git a/src/main/resources/static/assets/images/imprimelibros/presupuestador/estucado-mate-cubierta.png b/src/main/resources/static/assets/images/imprimelibros/presupuestador/estucado-mate-cubierta.png new file mode 100644 index 0000000..7178e36 Binary files /dev/null and b/src/main/resources/static/assets/images/imprimelibros/presupuestador/estucado-mate-cubierta.png differ diff --git a/src/main/resources/static/assets/images/imprimelibros/presupuestador/estucado-mate.png b/src/main/resources/static/assets/images/imprimelibros/presupuestador/estucado-mate.png new file mode 100644 index 0000000..77d6136 Binary files /dev/null and b/src/main/resources/static/assets/images/imprimelibros/presupuestador/estucado-mate.png differ diff --git a/src/main/resources/static/assets/images/imprimelibros/presupuestador/negroFoto.png b/src/main/resources/static/assets/images/imprimelibros/presupuestador/negroFoto.png new file mode 100644 index 0000000..f2bc8d8 Binary files /dev/null and b/src/main/resources/static/assets/images/imprimelibros/presupuestador/negroFoto.png differ diff --git a/src/main/resources/static/assets/images/imprimelibros/presupuestador/offset-ahuesado-volumen.png b/src/main/resources/static/assets/images/imprimelibros/presupuestador/offset-ahuesado-volumen.png new file mode 100644 index 0000000..297c607 Binary files /dev/null and b/src/main/resources/static/assets/images/imprimelibros/presupuestador/offset-ahuesado-volumen.png differ diff --git a/src/main/resources/static/assets/images/imprimelibros/presupuestador/offset-ahuesado.png b/src/main/resources/static/assets/images/imprimelibros/presupuestador/offset-ahuesado.png new file mode 100644 index 0000000..3c0f124 Binary files /dev/null and b/src/main/resources/static/assets/images/imprimelibros/presupuestador/offset-ahuesado.png differ diff --git a/src/main/resources/static/assets/images/imprimelibros/presupuestador/offset-blanco.png b/src/main/resources/static/assets/images/imprimelibros/presupuestador/offset-blanco.png new file mode 100644 index 0000000..29dc029 Binary files /dev/null and b/src/main/resources/static/assets/images/imprimelibros/presupuestador/offset-blanco.png differ diff --git a/src/main/resources/static/assets/images/imprimelibros/presupuestador/plantilla-cubierta.png b/src/main/resources/static/assets/images/imprimelibros/presupuestador/plantilla-cubierta.png new file mode 100644 index 0000000..8cb3255 Binary files /dev/null and b/src/main/resources/static/assets/images/imprimelibros/presupuestador/plantilla-cubierta.png differ diff --git a/src/main/resources/static/assets/images/imprimelibros/presupuestador/sinSolapasCubierta.png b/src/main/resources/static/assets/images/imprimelibros/presupuestador/sinSolapasCubierta.png new file mode 100644 index 0000000..c09917c Binary files /dev/null and b/src/main/resources/static/assets/images/imprimelibros/presupuestador/sinSolapasCubierta.png differ diff --git a/src/main/resources/static/assets/images/imprimelibros/presupuestador/tapa-blanda.jpg b/src/main/resources/static/assets/images/imprimelibros/presupuestador/tapa-blanda.jpg new file mode 100644 index 0000000..685af27 Binary files /dev/null and b/src/main/resources/static/assets/images/imprimelibros/presupuestador/tapa-blanda.jpg differ diff --git a/src/main/resources/static/assets/images/imprimelibros/presupuestador/tapa-dura-lomo-recto.jpg b/src/main/resources/static/assets/images/imprimelibros/presupuestador/tapa-dura-lomo-recto.jpg new file mode 100644 index 0000000..153bfa8 Binary files /dev/null and b/src/main/resources/static/assets/images/imprimelibros/presupuestador/tapa-dura-lomo-recto.jpg differ diff --git a/src/main/resources/static/assets/images/imprimelibros/presupuestador/tapa-dura-lomo-redondo.jpg b/src/main/resources/static/assets/images/imprimelibros/presupuestador/tapa-dura-lomo-redondo.jpg new file mode 100644 index 0000000..f0dd640 Binary files /dev/null and b/src/main/resources/static/assets/images/imprimelibros/presupuestador/tapa-dura-lomo-redondo.jpg differ diff --git a/src/main/resources/static/assets/js/pages/imprimelibros/languageBundle.js b/src/main/resources/static/assets/js/pages/imprimelibros/languageBundle.js new file mode 100644 index 0000000..a0f699d --- /dev/null +++ b/src/main/resources/static/assets/js/pages/imprimelibros/languageBundle.js @@ -0,0 +1,7 @@ +window.languageBundle.get = function (key, ...params) { + let text = this[key] || key; + params.forEach((val, i) => { + text = text.replace(`{${i}}`, val); + }); + return text; +}; diff --git a/src/main/resources/static/assets/js/pages/imprimelibros/presupuestador/presupuestador.js b/src/main/resources/static/assets/js/pages/imprimelibros/presupuestador/presupuestador.js new file mode 100644 index 0000000..4cf13dc --- /dev/null +++ b/src/main/resources/static/assets/js/pages/imprimelibros/presupuestador/presupuestador.js @@ -0,0 +1,111 @@ +class PresupuestoCliente { + + constructor() { + + // pestaña datos generales + this.titulo = $('#titulo'); + this.autor = $('#autor'); + this.isbn = $('#isbn'); + this.tirada1 = $('#tirada1'); + this.tirada2 = $('#tirada2'); + this.tirada3 = $('#tirada3'); + this.tirada4 = $('#tirada4'); + this.paginasNegro = $('#paginas-negro'); + this.paginasColor = $('#paginas-color') + this.btn_next_datos_generales = $('#next-datos-generales'); + this.datos_generales_alert = $('#datos-generales-alert'); + + // pestaña cubierta + this.btn_plantilla_cubierta = $('#btn-plantilla-cubierta'); + this.btn_impresion_cubierta_help = $('#impresion-cubierta-help'); + + + + } + + init() { + + this.initButtonsEventListeners(); + } + + initButtonsEventListeners() { + + this.btn_plantilla_cubierta.on('click', () => { + Swal.fire({ + position: 'top-end', + icon: 'info', + title: window.languageBundle.get('presupuesto.plantilla-cubierta'), + html: ` +
+ +
+
+ ${window.languageBundle.get('presupuesto.plantilla-cubierta-text')} +
+ `, + confirmButtonClass: 'btn btn-primary w-xs mt-2', + showConfirmButton: false, + showCloseButton: true + }); + }); + + this.btn_impresion_cubierta_help.on('click', () => { + Swal.fire({ + position: 'top-end', + icon: 'info', + title: window.languageBundle.get('presupuesto.impresion-cubierta'), + html: window.languageBundle.get('presupuesto.impresion-cubierta-help'), + confirmButtonClass: 'btn btn-primary w-xs mt-2', + showConfirmButton: false, + showCloseButton: true + }); + }); + + this.btn_next_datos_generales.on('click', () => { + this.nextDatosGenerales(); + }); + + } + + nextDatosGenerales() { + const data = { + titulo: this.titulo.val(), + autor: this.autor.val(), + isbn: this.isbn.val(), + tirada1: this.tirada1.val(), + tirada2: this.tirada2.val(), + tirada3: this.tirada3.val(), + tirada4: this.tirada4.val(), + paginasNegro: this.paginasNegro.val(), + paginasColor: this.paginasColor.val() + } + $.ajax({ + url: '/presupuesto/validar/datos-generales', + type: 'POST', + data: data, + success: (response) => { + this.datos_generales_alert.addClass('d-none'); + }, + error: (xhr, status, error) => { + this.datos_generales_alert.removeClass('d-none'); + this.datos_generales_alert.find('#datos-generales-alert-list').empty(); + const errors = xhr.responseJSON; + if (errors && typeof errors === 'object') { + Object.values(errors).forEach(errorMsg => { + this.datos_generales_alert.find('#datos-generales-alert-list').append(`
  • ${errorMsg}
  • `); + }); + } else { + this.datos_generales_alert.find('#datos-generales-alert-list').append('
  • Error desconocido. Por favor, inténtelo de nuevo más tarde.
  • '); + } + $(window).scrollTop(0); + } + }); + } + +} + + +document.addEventListener('DOMContentLoaded', function () { + const presupuestoCliente = new PresupuestoCliente(); + presupuestoCliente.init(); +}); \ No newline at end of file diff --git a/src/main/resources/static/assets/js/pages/sweetalerts.init.js b/src/main/resources/static/assets/js/pages/sweetalerts.init.js index 00a286a..e91cec0 100644 --- a/src/main/resources/static/assets/js/pages/sweetalerts.init.js +++ b/src/main/resources/static/assets/js/pages/sweetalerts.init.js @@ -247,7 +247,6 @@ if (document.getElementById("sa-position")) icon: 'success', title: 'Your work has been saved', showConfirmButton: false, - timer: 1500, showCloseButton: true }) }); diff --git a/src/main/resources/templates/imprimelibros/home.html b/src/main/resources/templates/imprimelibros/home.html index 6dbf065..7591e78 100644 --- a/src/main/resources/templates/imprimelibros/home.html +++ b/src/main/resources/templates/imprimelibros/home.html @@ -35,7 +35,11 @@
    +
    +
    diff --git a/src/main/resources/templates/imprimelibros/layout.html b/src/main/resources/templates/imprimelibros/layout.html index 9fcdf28..ebdbc4a 100644 --- a/src/main/resources/templates/imprimelibros/layout.html +++ b/src/main/resources/templates/imprimelibros/layout.html @@ -1,18 +1,13 @@ - + + + @@ -32,11 +27,13 @@ - + + + \ No newline at end of file diff --git a/src/main/resources/templates/imprimelibros/presupuestos/presupuestador-items/_cubierta.html b/src/main/resources/templates/imprimelibros/presupuestos/presupuestador-items/_cubierta.html new file mode 100644 index 0000000..bf55d84 --- /dev/null +++ b/src/main/resources/templates/imprimelibros/presupuestos/presupuestador-items/_cubierta.html @@ -0,0 +1,216 @@ +
    +
    +
    + +
    +
    + + +
    +
    +
    Tipo cubierta +
    +
    Seleccione el tipo de cubierta +
    +
    + +
    +
    +
    + + +
    + +
    + + +
    + +
    + + +
    +
    + +
    +
    + + +
    + +
    + + +
    + + +
    + +
    + + +
    +
    + +
    + + + +
    +
    + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + +
    +
    + + +
    +
    +
    Papel cubierta
    +
    + Seleccione el papel para la cubierta
    +
    + +
    + +
    +
    + + +
    + +
    + + +
    +
    +
    + +
    + + + +
    +
    +
    Gramaje cubierta +
    +
    + Gramaje del interior
    +
    + +
    +
    + + + + + + + + + + + + + + +
    + +
    +
    + + +
    + + +
    +
    \ No newline at end of file diff --git a/src/main/resources/templates/imprimelibros/presupuestos/presupuestador-items/_datos-generales.html b/src/main/resources/templates/imprimelibros/presupuestos/presupuestador-items/_datos-generales.html index 2f87aba..3a5c818 100644 --- a/src/main/resources/templates/imprimelibros/presupuestos/presupuestador-items/_datos-generales.html +++ b/src/main/resources/templates/imprimelibros/presupuestos/presupuestador-items/_datos-generales.html @@ -9,6 +9,14 @@
    + +
    @@ -38,23 +46,23 @@
    - - + +
    - +
    - +
    - +
    -

    +

    No puede mezclar tiradas menores de 30 unidades con mayores de 30 unidades

    @@ -63,7 +71,7 @@
    - @@ -82,9 +90,10 @@
    -
    - -
    @@ -146,11 +155,12 @@
    -
    -
    +
    +
    Fresado -
    Fresado (a partir de 32 páginas)
    +
    + Fresado (a partir de 32 páginas)
    @@ -159,7 +169,8 @@
    Cosido -
    Cosido (a partir de 32 páginas)
    +
    + Cosido (a partir de 32 páginas)
    @@ -168,7 +179,8 @@
    Grapado -
    Grapado (entre 12 y 40 páginas)
    +
    + Grapado (entre 12 y 40 páginas)
    @@ -177,7 +189,8 @@
    Espiral -
    Espiral (a partir de 20 páginas)
    +
    + Espiral (a partir de 20 páginas)
    @@ -186,7 +199,8 @@
    Wire-O -
    Wire-O (a partir de 20 páginas)
    +
    + Wire-O (a partir de 20 páginas)
    @@ -194,10 +208,11 @@
    -
    -
    - + +
    + +
    \ No newline at end of file diff --git a/src/main/resources/templates/imprimelibros/presupuestos/presupuestador-items/_interior.html b/src/main/resources/templates/imprimelibros/presupuestos/presupuestador-items/_interior.html new file mode 100644 index 0000000..e0435c1 --- /dev/null +++ b/src/main/resources/templates/imprimelibros/presupuestos/presupuestador-items/_interior.html @@ -0,0 +1,148 @@ +
    + +
    +
    +
    Tipo de impresión +
    +
    Elija entre calidad estándar + o premium
    +
    + +
    +
    +
    + Negro + +
    + +
    + NegroPremium + +
    + +
    + Color + +
    + +
    + ColorPremium + +
    +
    +
    +
    + + + +
    +
    +
    Papel interior
    +
    + Papel y gramaje del interior
    +
    + +
    + +
    +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    +
    +
    + +
    + + +
    +
    +
    Gramaje interior +
    +
    + Gramaje del interior
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + +
    + + +
    + +
    \ No newline at end of file diff --git a/src/main/resources/templates/imprimelibros/presupuestos/presupuestador.html b/src/main/resources/templates/imprimelibros/presupuestos/presupuestador.html index 22dc3d4..554bc2b 100644 --- a/src/main/resources/templates/imprimelibros/presupuestos/presupuestador.html +++ b/src/main/resources/templates/imprimelibros/presupuestos/presupuestador.html @@ -13,7 +13,7 @@ data-bs-toggle="pill" data-bs-target="#pills-general-data" type="button" role="tab" aria-controls="pills-general-data" aria-selected="true"> + class="ri-information-line fs-16 p-2 bg-soft-primary text-primary rounded-circle align-middle me-2"> @@ -40,8 +40,8 @@ data-bs-target="#pills-shipping" type="button" role="tab" aria-controls="pills-shipping" aria-selected="false"> - + class="ri-add-box-line fs-16 p-2 bg-soft-primary text-primary rounded-circle align-middle me-2"> + @@ -52,262 +52,24 @@ aria-labelledby="pills-general-data-tab">
    -
    -
    -
    -
    Shipping Information
    -

    Please fill all information below

    -
    - -
    -
    -
    -
    Saved Address
    -
    -
    - - -
    -
    -
    -
    -
    - - -
    -
    -
    - - Edit -
    - -
    -
    -
    -
    - - -
    -
    -
    - - Edit -
    - -
    -
    -
    - -
    -
    Shipping Method
    - -
    -
    -
    - - -
    -
    -
    -
    - - -
    -
    -
    -
    -
    - -
    - - -
    +
    + +
    -
    -
    -
    Payment Selection
    -

    Please select and enter your billing information

    -
    - -
    -
    - -
    -
    -
    -
    - - -
    -
    -
    - -
    - -
    -
    - -
    -
    -
    -
    - - - Full name as displayed on card -
    - -
    - - -
    - -
    - - -
    - -
    - - -
    -
    -
    -
    - Your transaction is - secured with SSL encryption -
    -
    - -
    - - -
    +
    + +
    -
    -
    - -
    - -
    -
    Thank you ! Your Order is Completed !
    -

    You will receive an order confirmation email with details - of your order.

    - -
    Order ID: VZ2451
    -
    -
    - +
    @@ -318,6 +80,7 @@
    +