mirror of
https://git.imnavajas.es/jjimenez/erp-imprimelibros.git
synced 2026-01-12 16:38:48 +00:00
trabajando en resumen
This commit is contained in:
@ -13,7 +13,6 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class skApiClient {
|
||||
@ -30,7 +29,6 @@ public class skApiClient {
|
||||
}
|
||||
|
||||
public String getPrice(Map<String, Object> requestBody) {
|
||||
|
||||
return performWithRetry(() -> {
|
||||
String url = this.skApiUrl + "api/calcular";
|
||||
|
||||
@ -46,35 +44,43 @@ public class skApiClient {
|
||||
entity,
|
||||
String.class);
|
||||
|
||||
return response.getBody();
|
||||
try {
|
||||
Map<String, Object> responseBody = new ObjectMapper().readValue(response.getBody(), Map.class);
|
||||
|
||||
if (responseBody.get("error") == null) {
|
||||
return new ObjectMapper().writeValueAsString(
|
||||
Map.of("data", responseBody.get("data")));
|
||||
} else {
|
||||
return "{\"error\": 1}";
|
||||
}
|
||||
} catch (JsonProcessingException e) {
|
||||
e.printStackTrace();
|
||||
return "{\"error\": 1}";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Integer getMaxSolapas(Map<String, Object> requestBody) {
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.setBearerAuth(authService.getToken());
|
||||
|
||||
Map<String, Object> request = new HashMap<>(requestBody);
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
|
||||
try {
|
||||
String jsonResponse = performWithRetry(() -> {
|
||||
|
||||
String url = this.skApiUrl + "api/calcular-solapas";
|
||||
|
||||
data.put("clienteId", request.get("clienteId"));
|
||||
data.put("tamanio", (Map<String, Object>) request.get("tamanio"));
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.setBearerAuth(authService.getToken()); // token actualizado
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("clienteId", requestBody.get("clienteId"));
|
||||
data.put("tamanio", requestBody.get("tamanio"));
|
||||
data.put("tirada", requestBody.get("tirada"));
|
||||
data.put("paginas", request.get("paginas"));
|
||||
data.put("paginasColor", request.get("paginasColor"));
|
||||
data.put("paginas", requestBody.get("paginas"));
|
||||
data.put("paginasColor", requestBody.get("paginasColor"));
|
||||
data.put("papelInteriorDiferente", 0);
|
||||
data.put("paginasCuadernillo", request.get("paginasCuadernillo"));
|
||||
data.put("tipo", request.get("tipo"));
|
||||
data.put("isColor", request.get("isColor"));
|
||||
data.put("isHq", request.get("isHq"));
|
||||
data.put("interior", request.get("interior"));
|
||||
data.put("paginasCuadernillo", requestBody.get("paginasCuadernillo"));
|
||||
data.put("tipo", requestBody.get("tipo"));
|
||||
data.put("isColor", requestBody.get("isColor"));
|
||||
data.put("isHq", requestBody.get("isHq"));
|
||||
data.put("interior", requestBody.get("interior"));
|
||||
|
||||
HttpEntity<Map<String, Object>> entity = new HttpEntity<>(data, headers);
|
||||
|
||||
@ -88,19 +94,19 @@ public class skApiClient {
|
||||
});
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
JsonNode root = mapper.readTree(jsonResponse);
|
||||
|
||||
if (root.get("data") == null || !root.get("data").isInt()) {
|
||||
throw new RuntimeException("Respuesta inesperada de calcular-solapas: " + jsonResponse);
|
||||
}
|
||||
int solapas = root.get("data").asInt();
|
||||
return solapas;
|
||||
|
||||
return root.get("data").asInt();
|
||||
|
||||
} catch (JsonProcessingException e) {
|
||||
// No se puede calcular el interior, por lo que las solapas seran el 80% del
|
||||
// ancho
|
||||
Map<String, Object> tamanio = (Map<String, Object>)data.get("tamanio");
|
||||
// Fallback al 80% del ancho
|
||||
Map<String, Object> tamanio = (Map<String, Object>) requestBody.get("tamanio");
|
||||
if (tamanio == null || tamanio.get("ancho") == null)
|
||||
throw new RuntimeException("Tamaño no válido en la solicitud: " + data);
|
||||
throw new RuntimeException("Tamaño no válido en la solicitud: " + requestBody);
|
||||
else {
|
||||
int ancho = (int) tamanio.get("ancho");
|
||||
return (int) Math.floor(ancho * 0.8); // 80% del ancho
|
||||
@ -108,6 +114,38 @@ public class skApiClient {
|
||||
}
|
||||
}
|
||||
|
||||
public Double getRetractilado(Map<String, Object> requestBody) {
|
||||
|
||||
String value = performWithRetry(() -> {
|
||||
String url = this.skApiUrl + "api/calcular-retractilado";
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.setBearerAuth(authService.getToken());
|
||||
|
||||
HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestBody, headers);
|
||||
|
||||
ResponseEntity<String> response = restTemplate.exchange(
|
||||
url,
|
||||
HttpMethod.POST,
|
||||
entity,
|
||||
String.class);
|
||||
|
||||
try {
|
||||
Map<String, Object> responseBody = new ObjectMapper().readValue(response.getBody(), Map.class);
|
||||
return responseBody.get("data").toString();
|
||||
} catch (JsonProcessingException e) {
|
||||
e.printStackTrace();
|
||||
return "0.0"; // Fallback en caso de error
|
||||
}
|
||||
});
|
||||
try {
|
||||
return Double.parseDouble(value);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new RuntimeException("Error al parsear el valor de retractilado: " + value, e);
|
||||
}
|
||||
}
|
||||
|
||||
/******************
|
||||
* PRIVATE METHODS
|
||||
******************/
|
||||
|
||||
@ -14,7 +14,7 @@ import jakarta.persistence.*;
|
||||
@Tamanio(groups = PresupuestoValidationGroups.DatosGenerales.class)
|
||||
@Entity
|
||||
@Table(name = "presupuesto")
|
||||
public class Presupuesto {
|
||||
public class Presupuesto implements Cloneable{
|
||||
|
||||
public enum TipoEncuadernacion {
|
||||
fresado, cosido, grapado, espiral, wireo
|
||||
@ -28,6 +28,15 @@ public class Presupuesto {
|
||||
tapaBlanda, tapaDura, tapaDuraLomoRedondo
|
||||
}
|
||||
|
||||
@Override
|
||||
public Presupuesto clone() {
|
||||
try {
|
||||
return (Presupuesto) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
@ -59,6 +68,9 @@ public class Presupuesto {
|
||||
@Column(name = "tirada4")
|
||||
private Integer tirada4;
|
||||
|
||||
@Column(name = "selected_tirada")
|
||||
private Integer selectedTirada;
|
||||
|
||||
@NotNull(message = "{presupuesto.errores.ancho}", groups = PresupuestoValidationGroups.DatosGenerales.class)
|
||||
@Column(name = "ancho")
|
||||
private Integer ancho;
|
||||
@ -134,10 +146,32 @@ public class Presupuesto {
|
||||
@NotNull(message = "{presupuesto.errores.acabado-cubierta}", groups = PresupuestoValidationGroups.Cubierta.class)
|
||||
@Column(name = "acabado")
|
||||
private Integer acabado = 1;
|
||||
|
||||
|
||||
// Getters y Setters
|
||||
@Column(name = "sobrecubierta")
|
||||
private Boolean sobrecubierta = false;
|
||||
@Column(name = "papel_sobrecubierta_id")
|
||||
private Integer papelSobrecubiertaId = 2;
|
||||
@Column(name = "gramaje_sobrecubierta")
|
||||
private Integer gramajeSobrecubierta = 170;
|
||||
@Column(name = "tamanio_solapas_sobrecubierta")
|
||||
private Integer tamanioSolapasSobrecubierta = 80;
|
||||
@Column(name = "acabado_sobrecubierta")
|
||||
private Integer acabadoSobrecubierta = 0; // 0: sin acabado,
|
||||
|
||||
@Column(name = "faja")
|
||||
private Boolean faja = false;
|
||||
@Column(name = "papel_faja_id")
|
||||
private Integer papelFajaId = 2;
|
||||
@Column(name = "gramaje_faja")
|
||||
private Integer gramajeFaja = 170;
|
||||
@Column(name = "tamanio_solapas_faja")
|
||||
private Integer tamanioSolapasFaja = 80;
|
||||
@Column(name = "acabado_faja")
|
||||
private Integer acabadoFaja = 0; // 0: sin acabado
|
||||
@Column(name = "alto_faja")
|
||||
private Integer altoFaja = 0;
|
||||
|
||||
// Getters y Setters
|
||||
public String getAutor() {
|
||||
return autor;
|
||||
}
|
||||
@ -382,4 +416,101 @@ public class Presupuesto {
|
||||
this.acabado = acabado;
|
||||
}
|
||||
|
||||
public Boolean getSobrecubierta() {
|
||||
return sobrecubierta;
|
||||
}
|
||||
|
||||
public void setSobrecubierta(Boolean sobrecubierta) {
|
||||
this.sobrecubierta = sobrecubierta;
|
||||
}
|
||||
|
||||
public Integer getPapelSobrecubiertaId() {
|
||||
return papelSobrecubiertaId;
|
||||
}
|
||||
|
||||
public void setPapelSobrecubiertaId(Integer papelSobrecubiertaId) {
|
||||
this.papelSobrecubiertaId = papelSobrecubiertaId;
|
||||
}
|
||||
|
||||
public Integer getGramajeSobrecubierta() {
|
||||
return gramajeSobrecubierta;
|
||||
}
|
||||
|
||||
public void setGramajeSobrecubierta(Integer gramajeSobrecubierta) {
|
||||
this.gramajeSobrecubierta = gramajeSobrecubierta;
|
||||
}
|
||||
|
||||
public Integer getTamanioSolapasSobrecubierta() {
|
||||
return tamanioSolapasSobrecubierta;
|
||||
}
|
||||
|
||||
public void setTamanioSolapasSobrecubierta(Integer tamanioSolapasSobrecubierta) {
|
||||
this.tamanioSolapasSobrecubierta = tamanioSolapasSobrecubierta;
|
||||
}
|
||||
|
||||
public Integer getAcabadoSobrecubierta() {
|
||||
return acabadoSobrecubierta;
|
||||
}
|
||||
|
||||
public void setAcabadoSobrecubierta(Integer acabadoSobrecubierta) {
|
||||
this.acabadoSobrecubierta = acabadoSobrecubierta;
|
||||
}
|
||||
|
||||
public Boolean getFaja() {
|
||||
return faja;
|
||||
}
|
||||
|
||||
public void setFaja(Boolean faja) {
|
||||
this.faja = faja;
|
||||
}
|
||||
|
||||
public Integer getPapelFajaId() {
|
||||
return papelFajaId;
|
||||
}
|
||||
|
||||
public void setPapelFajaId(Integer papelFajaId) {
|
||||
this.papelFajaId = papelFajaId;
|
||||
}
|
||||
|
||||
public Integer getGramajeFaja() {
|
||||
return gramajeFaja;
|
||||
}
|
||||
|
||||
public void setGramajeFaja(Integer gramajeFaja) {
|
||||
this.gramajeFaja = gramajeFaja;
|
||||
}
|
||||
|
||||
public Integer getTamanioSolapasFaja() {
|
||||
return tamanioSolapasFaja;
|
||||
}
|
||||
|
||||
public void setTamanioSolapasFaja(Integer tamanioSolapasFaja) {
|
||||
this.tamanioSolapasFaja = tamanioSolapasFaja;
|
||||
}
|
||||
|
||||
public Integer getAcabadoFaja() {
|
||||
return acabadoFaja;
|
||||
}
|
||||
|
||||
public void setAcabadoFaja(Integer acabadoFaja) {
|
||||
this.acabadoFaja = acabadoFaja;
|
||||
}
|
||||
|
||||
public Integer getAltoFaja() {
|
||||
return altoFaja;
|
||||
}
|
||||
|
||||
public void setAltoFaja(Integer altoFaja) {
|
||||
this.altoFaja = altoFaja;
|
||||
}
|
||||
|
||||
public Integer getSelectedTirada() {
|
||||
return selectedTirada;
|
||||
}
|
||||
|
||||
public void setSelectedTirada(Integer selectedTirada) {
|
||||
this.selectedTirada = selectedTirada;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -6,16 +6,18 @@ import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.imprimelibros.erp.externalApi.skApiClient;
|
||||
import com.imprimelibros.erp.presupuesto.classes.ImagenPresupuesto;
|
||||
import com.imprimelibros.erp.presupuesto.validation.PresupuestoValidationGroups;
|
||||
@ -30,6 +32,9 @@ public class PresupuestoController {
|
||||
@Autowired
|
||||
protected skApiClient apiClient;
|
||||
|
||||
@Autowired
|
||||
protected MessageSource messageSource;
|
||||
|
||||
@PostMapping("/public/validar/datos-generales")
|
||||
public ResponseEntity<?> validarDatosGenerales(
|
||||
@Validated(PresupuestoValidationGroups.DatosGenerales.class) Presupuesto presupuesto,
|
||||
@ -80,6 +85,63 @@ public class PresupuestoController {
|
||||
return ResponseEntity.ok(resultado);
|
||||
}
|
||||
|
||||
@PostMapping("/public/validar/cubierta")
|
||||
public ResponseEntity<?> validarCubierta(
|
||||
@Validated(PresupuestoValidationGroups.Cubierta.class) Presupuesto presupuesto,
|
||||
BindingResult result, Locale locale) {
|
||||
|
||||
Map<String, String> errores = new HashMap<>();
|
||||
|
||||
// errores de campos individuales
|
||||
result.getFieldErrors().forEach(error -> errores.put(error.getField(), error.getDefaultMessage()));
|
||||
|
||||
// errores globales (@ConsistentTiradas...)
|
||||
result.getGlobalErrors().forEach(error -> errores.put("global", error.getDefaultMessage()));
|
||||
|
||||
if (!errores.isEmpty()) {
|
||||
return ResponseEntity.badRequest().body(errores);
|
||||
}
|
||||
|
||||
HashMap<String, Object> price = new HashMap<>();
|
||||
String priceStr = apiClient.getPrice(presupuestoService.toSkApiRequest(presupuesto));
|
||||
|
||||
try {
|
||||
price = new ObjectMapper().readValue(priceStr, new TypeReference<>() {
|
||||
});
|
||||
} catch (JsonProcessingException e) {
|
||||
price = new HashMap<>();
|
||||
price.put("error", messageSource.getMessage("presupuesto.error-obtener-precio", null, locale));
|
||||
}
|
||||
if (!price.containsKey("data")) {
|
||||
return ResponseEntity.badRequest().body(messageSource.getMessage("presupuesto.error-obtener-precio", null, locale));
|
||||
}
|
||||
return ResponseEntity.ok(price.get("data"));
|
||||
}
|
||||
|
||||
@PostMapping("/public/validar/seleccion-tirada")
|
||||
public ResponseEntity<?> validarSeleccionTirada(
|
||||
Presupuesto presupuesto,
|
||||
BindingResult result, Locale locale) {
|
||||
|
||||
Map<String, String> errores = new HashMap<>();
|
||||
|
||||
// errores de campos individuales
|
||||
result.getFieldErrors().forEach(error -> errores.put(error.getField(), error.getDefaultMessage()));
|
||||
|
||||
// errores globales (@ConsistentTiradas...)
|
||||
result.getGlobalErrors().forEach(error -> errores.put("global", error.getDefaultMessage()));
|
||||
|
||||
if (!errores.isEmpty()) {
|
||||
return ResponseEntity.badRequest().body(errores);
|
||||
}
|
||||
|
||||
Map<String, Object> resultado = new HashMap<>();
|
||||
// servicios extra
|
||||
resultado.putAll(presupuestoService.obtenerServiciosExtras(presupuesto, locale, apiClient));
|
||||
|
||||
return ResponseEntity.ok(resultado);
|
||||
}
|
||||
|
||||
@PostMapping("/public/get-papel-interior")
|
||||
public ResponseEntity<?> getPapelInterior(
|
||||
@Validated(PresupuestoValidationGroups.Interior.class) Presupuesto presupuesto,
|
||||
@ -212,4 +274,24 @@ public class PresupuestoController {
|
||||
return ResponseEntity.ok(resultado);
|
||||
}
|
||||
|
||||
@PostMapping("/public/get-price")
|
||||
public ResponseEntity<?> getPrice(
|
||||
Presupuesto presupuesto,
|
||||
BindingResult result, Locale locale) {
|
||||
|
||||
Map<String, String> errores = new HashMap<>();
|
||||
// errores de campos individuales
|
||||
result.getFieldErrors().forEach(error -> errores.put(error.getField(), error.getDefaultMessage()));
|
||||
// errores globales (@ConsistentTiradas...)
|
||||
result.getGlobalErrors().forEach(error -> errores.put("global", error.getDefaultMessage()));
|
||||
if (!errores.isEmpty()) {
|
||||
return ResponseEntity.badRequest().body(errores);
|
||||
}
|
||||
String price = apiClient.getPrice(presupuestoService.toSkApiRequest(presupuesto));
|
||||
if (price == null || price.isEmpty()) {
|
||||
return ResponseEntity.badRequest().body("No se pudo obtener el precio. Intente nuevamente.");
|
||||
}
|
||||
return ResponseEntity.ok(price);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,15 +8,21 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.Locale;
|
||||
import java.text.NumberFormat;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.imprimelibros.erp.configurationERP.VariableService;
|
||||
import com.imprimelibros.erp.presupuesto.Presupuesto.TipoCubierta;
|
||||
import com.imprimelibros.erp.presupuesto.classes.ImagenPresupuesto;
|
||||
import com.imprimelibros.erp.presupuesto.classes.PresupuestadorItems;
|
||||
import com.imprimelibros.erp.externalApi.skApiClient;
|
||||
|
||||
@Service
|
||||
public class PresupuestoService {
|
||||
@ -27,6 +33,9 @@ public class PresupuestoService {
|
||||
@Autowired
|
||||
protected MessageSource messageSource;
|
||||
|
||||
@Autowired
|
||||
protected skApiClient skApiClient;
|
||||
|
||||
private final PresupuestadorItems presupuestadorItems;
|
||||
|
||||
public PresupuestoService(PresupuestadorItems presupuestadorItems) {
|
||||
@ -228,7 +237,7 @@ public class PresupuestoService {
|
||||
|
||||
List<String> gramajes = new ArrayList<>();
|
||||
|
||||
final int CARTULINA_GRAFICA_ID = 3;
|
||||
final int CARTULINA_GRAFICA_ID = 5;
|
||||
final int ESTUCADO_MATE_ID = 2;
|
||||
|
||||
if (presupuesto.getPapelCubiertaId() != null && presupuesto.getPapelCubiertaId() == CARTULINA_GRAFICA_ID) {
|
||||
@ -269,17 +278,11 @@ public class PresupuestoService {
|
||||
"gramajeCubierta", presupuesto.getGramajeCubierta(),
|
||||
"carasImpresion", presupuesto.getCubiertaCaras(),
|
||||
"solapas", presupuesto.getSolapasCubierta() ? presupuesto.getTamanioSolapasCubierta() : 0,
|
||||
"acabado", 0, //// Añadir acabados
|
||||
"acabado", presupuesto.getAcabado(),
|
||||
"cabezada", presupuesto.getCabezada(),
|
||||
"lomoRedondo", presupuesto.getTipoCubierta() == TipoCubierta.tapaDuraLomoRedondo ? 1 : 0);
|
||||
|
||||
/*
|
||||
* Map<String, Object> sobrecubierta = new HashMap<>();
|
||||
* sobrecubierta.put("papel", "2");
|
||||
* sobrecubierta.put("gramaje", 170);
|
||||
* sobrecubierta.put("solapas", 80);
|
||||
* sobrecubierta.put("acabado", null);
|
||||
*
|
||||
* Map<String, Object> servicios = Map.of(
|
||||
* "retractilado", 0,
|
||||
* "retractilado5", 0,
|
||||
@ -303,9 +306,25 @@ public class PresupuestoService {
|
||||
body.put("paginasCuadernillo", SK_PAGINAS_CUADERNILLO);
|
||||
body.put("interior", interior);
|
||||
body.put("cubierta", cubierta);
|
||||
// body.put("sobrecubierta", sobrecubierta);
|
||||
body.put("guardas", null);
|
||||
body.put("faja", false);
|
||||
if (presupuesto.getSobrecubierta()) {
|
||||
Map<String, Object> sobrecubierta = new HashMap<>();
|
||||
sobrecubierta.put("papel", presupuesto.getPapelSobrecubiertaId());
|
||||
sobrecubierta.put("gramaje", presupuesto.getGramajeSobrecubierta());
|
||||
sobrecubierta.put("solapas", presupuesto.getTamanioSolapasSobrecubierta());
|
||||
sobrecubierta.put("acabado", presupuesto.getAcabadoSobrecubierta());
|
||||
body.put("sobrecubierta", sobrecubierta);
|
||||
}
|
||||
|
||||
if (presupuesto.getFaja()) {
|
||||
Map<String, Object> faja = new HashMap<>();
|
||||
faja.put("papel", presupuesto.getPapelFajaId());
|
||||
faja.put("gramaje", presupuesto.getGramajeFaja());
|
||||
faja.put("solapas", presupuesto.getTamanioSolapasFaja());
|
||||
faja.put("acabado", presupuesto.getAcabadoFaja());
|
||||
faja.put("alto", presupuesto.getAltoFaja());
|
||||
body.put("faja", faja);
|
||||
}
|
||||
// body.put("servicios", servicios);
|
||||
|
||||
return body;
|
||||
@ -372,7 +391,8 @@ public class PresupuestoService {
|
||||
});
|
||||
opciones.add(new HashMap<>() {
|
||||
{
|
||||
put("name", messageSource.getMessage("presupuesto.acabado-plastificado-mate-1c-antirrayado", null, locale));
|
||||
put("name",
|
||||
messageSource.getMessage("presupuesto.acabado-plastificado-mate-1c-antirrayado", null, locale));
|
||||
put("sk-id", 8);
|
||||
}
|
||||
});
|
||||
@ -405,4 +425,157 @@ public class PresupuestoService {
|
||||
return resultado;
|
||||
}
|
||||
|
||||
public Map<String, Object> aplicarMargenTiradas(Map<String, Object> data) {
|
||||
|
||||
// implementar margenes
|
||||
return (Map<String, Object>) data;
|
||||
}
|
||||
|
||||
public String obtenerPrecioRetractilado(Presupuesto presupuesto, Locale locale) {
|
||||
Integer[] tiradas = presupuesto.getTiradas();
|
||||
Integer tirada_min = Arrays.stream(tiradas)
|
||||
.filter(Objects::nonNull)
|
||||
.min(Integer::compareTo)
|
||||
.orElse(0);
|
||||
Map<String, Object> requestBody = new HashMap<>();
|
||||
requestBody.put("tirada",
|
||||
presupuesto.getSelectedTirada() != null ? presupuesto.getSelectedTirada() : tirada_min);
|
||||
Double precio_retractilado = skApiClient.getRetractilado(requestBody);
|
||||
return precio_retractilado != null
|
||||
? NumberFormat.getNumberInstance(locale)
|
||||
.format(Math.round(precio_retractilado * 100.0) / 100.0)
|
||||
: "0,00";
|
||||
}
|
||||
|
||||
public Map<String, Object> obtenerServiciosExtras(Presupuesto presupuesto, Locale locale, skApiClient apiClient) {
|
||||
|
||||
List<Object> opciones = new ArrayList<>();
|
||||
|
||||
Double price_prototipo = this.obtenerPrototipo(presupuesto, apiClient);
|
||||
|
||||
opciones.add(new HashMap<String, String>() {
|
||||
{
|
||||
put("id", "retractilado");
|
||||
put("title", messageSource.getMessage("presupuesto.extras-retractilado", null, locale));
|
||||
put("description", "");
|
||||
put("price", obtenerPrecioRetractilado(presupuesto, locale));
|
||||
put("priceUnit", messageSource.getMessage("app.currency-symbol", null, locale));
|
||||
}
|
||||
});
|
||||
opciones.add(new HashMap<String, String>() {
|
||||
{
|
||||
put("id", "service-isbn");
|
||||
put("title", messageSource.getMessage("presupuesto.extras-isbn", null, locale));
|
||||
put("description", "");
|
||||
put("price", "30");
|
||||
put("priceUnit", messageSource.getMessage("app.currency-symbol", null, locale));
|
||||
}
|
||||
});
|
||||
opciones.add(new HashMap<String, String>() {
|
||||
{
|
||||
put("id", "deposito-legal");
|
||||
put("title", messageSource.getMessage("presupuesto.extras-deposito-legal", null, locale));
|
||||
put("description",
|
||||
messageSource.getMessage("presupuesto.extras-deposito-legal-descripcion", null, locale));
|
||||
put("price", "30");
|
||||
put("priceUnit", messageSource.getMessage("app.currency-symbol", null, locale));
|
||||
}
|
||||
});
|
||||
opciones.add(new HashMap<String, String>() {
|
||||
{
|
||||
put("id", "revision-archivos");
|
||||
put("title", messageSource.getMessage("presupuesto.extras-revision-archivos", null, locale));
|
||||
put("description", "");
|
||||
put("price", "50");
|
||||
put("priceUnit", messageSource.getMessage("app.currency-symbol", null, locale));
|
||||
}
|
||||
});
|
||||
opciones.add(new HashMap<String, String>() {
|
||||
{
|
||||
put("id", "maquetacion-cubierta");
|
||||
put("title", messageSource.getMessage("presupuesto.extras-maquetacion-cubierta", null, locale));
|
||||
put("description", "");
|
||||
put("price", "50");
|
||||
put("priceUnit", messageSource.getMessage("app.currency-symbol", null, locale));
|
||||
}
|
||||
});
|
||||
opciones.add(new HashMap<String, String>() {
|
||||
{
|
||||
put("id", "ferro-digital");
|
||||
put("title", messageSource.getMessage("presupuesto.extras-ferro-digital", null, locale));
|
||||
put("description", "");
|
||||
put("price", "0");
|
||||
put("priceUnit", messageSource.getMessage("app.currency-symbol", null, locale));
|
||||
put("checked", "true");
|
||||
put("allowChange", "false");
|
||||
put("ribbonText", messageSource.getMessage("presupuesto.extras-ferro-digital-ribbon", null, locale));
|
||||
}
|
||||
});
|
||||
opciones.add(new HashMap<String, String>() {
|
||||
{
|
||||
put("id", "ejemplar-prueba");
|
||||
put("title", messageSource.getMessage("presupuesto.extras-ejemplar-prueba", null, locale));
|
||||
put("description", "");
|
||||
if(price_prototipo == 0.0) {
|
||||
put("price", messageSource.getMessage("presupuesto.consultar-soporte", null, locale));
|
||||
put("priceUnit", "");
|
||||
} else {
|
||||
put("price", NumberFormat.getNumberInstance(locale)
|
||||
.format(Math.round(price_prototipo * 100.0) / 100.0));
|
||||
put("priceUnit", messageSource.getMessage("app.currency-symbol", null, locale));
|
||||
}
|
||||
}
|
||||
});
|
||||
opciones.add(new HashMap<String, String>() {
|
||||
{
|
||||
put("id", "marcapaginas");
|
||||
put("title", messageSource.getMessage("presupuesto.extras-marcapaginas", null, locale));
|
||||
put("description", "");
|
||||
put("price", messageSource.getMessage("presupuesto.extras-calcular", null, locale));
|
||||
}
|
||||
});
|
||||
opciones.add(new HashMap<String, String>() {
|
||||
{
|
||||
put("id", "maquetacion");
|
||||
put("title", messageSource.getMessage("presupuesto.extras-maquetacion", null, locale));
|
||||
put("description", "");
|
||||
put("price", messageSource.getMessage("presupuesto.extras-calcular", null, locale));
|
||||
}
|
||||
});
|
||||
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
response.put("servicios_extra", opciones);
|
||||
return response;
|
||||
}
|
||||
|
||||
private Double obtenerPrototipo(Presupuesto presupuesto, skApiClient apiClient) {
|
||||
|
||||
// Obtenemos el precio de 1 unidad para el ejemplar de prueba
|
||||
HashMap<String, Object> price = new HashMap<>();
|
||||
// make a copy of "presupuesto" to avoid modifying the original object
|
||||
Presupuesto presupuestoTemp = presupuesto.clone();
|
||||
presupuestoTemp.setTirada1(1);
|
||||
presupuestoTemp.setTirada2(null);
|
||||
presupuestoTemp.setTirada3(null);
|
||||
presupuestoTemp.setTirada4(null);
|
||||
if (presupuestoTemp.getTipoImpresion() == Presupuesto.TipoImpresion.color) {
|
||||
presupuestoTemp.setTipoImpresion(Presupuesto.TipoImpresion.colorhq);
|
||||
} else if (presupuestoTemp.getTipoImpresion() == Presupuesto.TipoImpresion.negro) {
|
||||
presupuestoTemp.setTipoImpresion(Presupuesto.TipoImpresion.negrohq);
|
||||
}
|
||||
String priceStr = apiClient.getPrice(this.toSkApiRequest(presupuestoTemp));
|
||||
Double price_prototipo = 0.0;
|
||||
try {
|
||||
price = new ObjectMapper().readValue(priceStr, new TypeReference<>() {
|
||||
});
|
||||
price_prototipo = ((List<Double>) ((Map<String, Object>) price.get("data")).get("precios")).get(0);
|
||||
if (price_prototipo < 25) {
|
||||
price_prototipo = 25.0;
|
||||
}
|
||||
|
||||
} catch (JsonProcessingException e) {
|
||||
} catch (Exception exception) {
|
||||
}
|
||||
return price_prototipo;
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,7 +112,7 @@ public class PresupuestadorItems {
|
||||
"/assets/images/imprimelibros/presupuestador/cartulina-grafica.png",
|
||||
"",
|
||||
messageSource.getMessage("presupuesto.cartulina-grafica-cubierta", null, locale),
|
||||
Map.of("sk-id", "3"),
|
||||
Map.of("sk-id", "5"),
|
||||
false);
|
||||
}
|
||||
|
||||
|
||||
1
src/main/resources/i18n/app_en.properties
Normal file
1
src/main/resources/i18n/app_en.properties
Normal file
@ -0,0 +1 @@
|
||||
app.currency-symbol=€
|
||||
1
src/main/resources/i18n/app_es.properties
Normal file
1
src/main/resources/i18n/app_es.properties
Normal file
@ -0,0 +1 @@
|
||||
app.currency-symbol=€
|
||||
@ -1,6 +1,7 @@
|
||||
presupuesto.datos-generales=Datos Generales
|
||||
presupuesto.interior=Interior
|
||||
presupuesto.cubierta=Cubierta
|
||||
presupuesto.seleccion-tirada=Seleccion de tirada
|
||||
presupuesto.extras=Extras
|
||||
|
||||
# Pestaña datos generales de presupuesto
|
||||
@ -85,9 +86,12 @@ presupuesto.estucado-mate-cubierta=Estucado mate
|
||||
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
|
||||
presupuesto.continuar-seleccion-tirada=Continuar a selección de tirada
|
||||
presupuesto.offset=Offset
|
||||
presupuesto.estucado=Estucado
|
||||
presupuesto.verjurado=Verjurado
|
||||
presupuesto.verjurado-blanco-natural=Verjurado blanco natural
|
||||
presupuesto.verjurado-ahuesado=Verjurado ahuesado
|
||||
presupuesto.acabado=Acabado
|
||||
presupuesto.acabado-cubierta-descripcion=Seleccione el acabado para la cubierta
|
||||
presupuesto.acabado-cubierta-aviso=La falta de plastificado en la cubierta puede comprometer su calidad, ya que aumenta el riesgo de agrietamiento en los pliegues o hendidos, afectando su apariencia y resistencia.
|
||||
@ -99,6 +103,55 @@ presupuesto.acabado-plastificado-mate-uvi=Plastificado Mate 1/C + Reserva UVI
|
||||
presupuesto.acabado-plastificado-mate-uvi3d=Plastificado Mate 1/C + Reserva UVI 3D
|
||||
presupuesto.acabado-plastificado-mate-uvi-braile=Plastificado Mate 1/C + Reserva UVI Braille
|
||||
presupuesto.acabado-plastificado-sandy-1c=Plastificado Sandy 1/C (tacto arena)
|
||||
presupuesto.cubierta-extras=Extras de cubierta
|
||||
presupuesto.cubierta-extras-descripcion=Seleccione las opciones adicionales para la cubierta
|
||||
presupuesto.sobrecubierta=Sobrecubierta
|
||||
presupuesto.sobrecubierta-papel=Papel sobrecubierta
|
||||
presupuesto.sobrecubierta-solapas=Tamaño solapas sobrecubierta
|
||||
presupuesto.faja=Faja
|
||||
presupuesto.faja-papel=Papel faja
|
||||
presupuesto.faja-solapas=Tamaño solapas faja
|
||||
presupuesto.faja-alto=Alto faja
|
||||
|
||||
#pestaña seleccion-tirada
|
||||
presupuesto.seleccion-tirada-descripcion=Seleccione la tirada deseada
|
||||
presupuesto.total=Total
|
||||
presupuesto.precio-unidad=Precio por unidad
|
||||
presupuesto.seleccionar-tirada=Seleccionar tirada
|
||||
presupuesto.tirada-seleccionada=Seleccionada
|
||||
presupuesto.unidades=UNIDADES
|
||||
presupuesto.volver-seleccion-tirada=Volver a selección de tirada
|
||||
presupuesto.continuar-extras-libro=Continuar a extras del libro
|
||||
presupuesto.error-obtener-precio=No se pudo obtener el precio para los datos introducidos. Por favor, contacte con el soporte técnico.
|
||||
|
||||
#pestaña extras del libro
|
||||
presupuesto.extras=Servicios Extras
|
||||
presupuesto.extras-descripcion=Seleccione los servicios adicionales que desea añadir al presupuesto
|
||||
presupuesto.extras-retractilado=Retractilado
|
||||
presupuesto.extras-isbn=ISBN
|
||||
presupuesto.extras-deposito-legal=Depósito Legal
|
||||
presupuesto.extras-deposito-legal-descripcion=Se añadirán 4 ejemplares a la tirada
|
||||
presupuesto.extras-revision-archivos=Revisión de archivos
|
||||
presupuesto.extras-maquetacion-cubierta=Maquetación de cubierta
|
||||
presupuesto.extras-ferro-digital=Ferro Digital
|
||||
presupuesto.extras-ejemplar-prueba=Ejemplar de prueba
|
||||
presupuesto.extras-marcapaginas=Marcapáginas
|
||||
presupuesto.extras-maquetacion=Maquetación
|
||||
presupuesto.extras-ferro-digital-ribbon=Incluido
|
||||
presupuesto.extras-calcular=Calcular
|
||||
presupuesto.volver-cubierta=Volver a diseño cubierta
|
||||
presupuesto.finalizar=Finalizar presupuesto
|
||||
presupuesto.calcular-presupuesto=Calcular presupuesto
|
||||
presupuesto.consultar-soporte=Consultar con soporte
|
||||
|
||||
# Resumen del presupuesto
|
||||
presupuesto.resumen-presupuesto=Resumen presupuesto
|
||||
presupuesto.resumen-libro=Libro
|
||||
presupuesto.resumen-encuadernacion=Encuadernación
|
||||
presupuesto.interior-libro=Interior del libro
|
||||
presupuesto.cubierta-libro=Cubierta del libro
|
||||
presupuesto.extras-libro=Extras del libro
|
||||
presupuesto.paginas=Páginas
|
||||
|
||||
# Errores
|
||||
presupuesto.errores-title=Corrija los siguientes errores:
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
text-align: center;
|
||||
|
||||
/* Tamaño adaptable */
|
||||
width: 100%;
|
||||
max-width: 200px;
|
||||
width: 100%;
|
||||
max-width: 200px;
|
||||
|
||||
/* Para evitar que la imagen sobresalga al hacer zoom */
|
||||
overflow: hidden;
|
||||
@ -30,7 +30,7 @@
|
||||
|
||||
/* === Imagen interna === */
|
||||
.image-container img {
|
||||
max-width: 100%;
|
||||
max-width: 100%;
|
||||
max-height: 150px;
|
||||
display: block;
|
||||
transform-origin: center center;
|
||||
@ -44,10 +44,21 @@
|
||||
|
||||
/* Keyframes para la animación */
|
||||
@keyframes zoomPop {
|
||||
0% { transform: scale(1); }
|
||||
40% { transform: scale(0.85); }
|
||||
80% { transform: scale(1.05); }
|
||||
100% { transform: scale(1); }
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
40% {
|
||||
transform: scale(0.85);
|
||||
}
|
||||
|
||||
80% {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.image-container:hover {
|
||||
@ -61,15 +72,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
.gramaje-radio{
|
||||
.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 */
|
||||
min-width: 70px;
|
||||
/* Ancho mínimo */
|
||||
min-height: 70px;
|
||||
/* Alto mínimo */
|
||||
max-width: 70px;
|
||||
/* Ancho máximo */
|
||||
max-height: 70px;
|
||||
/* Alto máximo */
|
||||
}
|
||||
|
||||
@keyframes fadeInUpBounce {
|
||||
@ -77,13 +92,16 @@
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
|
||||
60% {
|
||||
opacity: 1;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
|
||||
80% {
|
||||
transform: translateY(5px);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
@ -93,4 +111,240 @@
|
||||
animation: fadeInUpBounce 0.6s ease-out both;
|
||||
animation-delay: 0.1s;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.service-option {
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease-in-out;
|
||||
border: 1px solid #d0d7e5;
|
||||
border-radius: 0.5rem;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.service-option.checked {
|
||||
border-color: #4b7bec;
|
||||
background-color: #f0f5ff;
|
||||
box-shadow: 0 0 0 2px #4b7bec inset;
|
||||
}
|
||||
|
||||
.service-option .price {
|
||||
font-weight: 600;
|
||||
font-size: 1rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.service-desc {
|
||||
min-height: 2.2rem;
|
||||
/* ajusta según el tamaño de fuente que uses */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.service-checkbox {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.btn-check-service+.btn {
|
||||
position: relative;
|
||||
/* <-- Esto es lo más importante */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
white-space: normal;
|
||||
line-height: 1.2;
|
||||
min-height: 180px;
|
||||
padding: 1rem 0.75rem;
|
||||
border-radius: 0.5rem;
|
||||
color: #4b7bec;
|
||||
border: 1px solid #4b7bec;
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
/* ESTILO CUANDO ESTÁ MARCADO */
|
||||
.btn-check-service:checked+.btn {
|
||||
background-color: #4b7bec;
|
||||
color: #ffffff !important;
|
||||
border-color: #4b7bec;
|
||||
}
|
||||
|
||||
/* Forzamos el color blanco en los subelementos */
|
||||
.btn-check-service:checked+.btn .service-title,
|
||||
.btn-check-service:checked+.btn .service-desc,
|
||||
.btn-check-service:checked+.btn .service-price {
|
||||
color: #ffffff !important;
|
||||
}
|
||||
|
||||
/* Forzamos el color azul cuando no está marcado */
|
||||
.btn-check-service+.btn .service-title,
|
||||
.btn-check-service+.btn .service-desc,
|
||||
.btn-check-service+.btn .service-price {
|
||||
color: #4b7bec;
|
||||
}
|
||||
|
||||
/* ribbon-service */
|
||||
.ribbon-service {
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
right: -5px;
|
||||
overflow: hidden;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.ribbon-service span {
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: 120px;
|
||||
padding: 5px 0;
|
||||
background: #f25c5c;
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
transform: rotate(45deg);
|
||||
top: 20px;
|
||||
right: -30px;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
|
||||
/* ===== Tiradas (pricing cards) ===== */
|
||||
.tirada-card {
|
||||
--il-accent: #4b7bec;
|
||||
--radius: 18px;
|
||||
--sel-scale-y: 1.12;
|
||||
/* cuánto más alta la seleccionada (crece arriba y abajo) */
|
||||
|
||||
/* círculo */
|
||||
--arc-w: 280px;
|
||||
--arc-h: 190px;
|
||||
--arc-y: -23px;
|
||||
/* tu valor */
|
||||
--arc-stop: 74%;
|
||||
|
||||
border: 1px solid #e9ecef;
|
||||
border-radius: var(--radius);
|
||||
background-color: #fff;
|
||||
background-image: radial-gradient(var(--arc-w) var(--arc-h) at 50% var(--arc-y),
|
||||
rgba(75, 126, 236, .24) 0 var(--arc-stop),
|
||||
transparent calc(var(--arc-stop) + 1%));
|
||||
|
||||
padding: 1.25rem 1.25rem 1rem;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
box-shadow: 0 4px 14px rgba(17, 24, 39, .06);
|
||||
overflow: hidden;
|
||||
/* integra la línea inferior */
|
||||
transform-origin: center center;
|
||||
/* ⟵ crecer hacia arriba y hacia abajo */
|
||||
will-change: transform;
|
||||
transition: transform .22s ease, box-shadow .22s ease, border-color .22s ease, background .22s ease;
|
||||
}
|
||||
|
||||
/* sin elevación al hover */
|
||||
.tirada-card:hover {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
/* Tipografías */
|
||||
.tirada-card .title {
|
||||
font-weight: 700;
|
||||
letter-spacing: .04em;
|
||||
font-size: .9rem;
|
||||
color: #4b7bec;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.tirada-card .price-big {
|
||||
font-size: 2rem;
|
||||
font-weight: 800;
|
||||
line-height: 1.1;
|
||||
margin: .35rem 0 .15rem;
|
||||
color: #4b7bec;
|
||||
}
|
||||
|
||||
.tirada-card .per {
|
||||
font-size: .85rem;
|
||||
color: #7f8fa9;
|
||||
}
|
||||
|
||||
.tirada-card .price-row {
|
||||
margin-top: .75rem;
|
||||
}
|
||||
|
||||
.tirada-card .muted {
|
||||
color: #8e9bb3;
|
||||
font-size: .9rem;
|
||||
}
|
||||
|
||||
/* Botón */
|
||||
.tirada-card .btn-select-tirada {
|
||||
margin-top: 1rem;
|
||||
border-radius: 999px;
|
||||
padding: .6rem 1rem;
|
||||
font-weight: 600;
|
||||
border: 2px solid var(--il-accent);
|
||||
color: var(--il-accent);
|
||||
background: transparent;
|
||||
width: 100%;
|
||||
transition: background .2s ease, color .2s ease;
|
||||
}
|
||||
|
||||
/* ===== Seleccionada (más alta en Y, sin elevar; crece arriba y abajo) ===== */
|
||||
.tirada-card.selected {
|
||||
transform: scaleY(var(--sel-scale-y));
|
||||
/* ⟵ crecimiento simétrico vertical */
|
||||
z-index: 2;
|
||||
box-shadow: 0 18px 48px rgba(75, 126, 236, .32);
|
||||
border-color: var(--il-accent);
|
||||
|
||||
/* círculo sólido */
|
||||
background-image: radial-gradient(var(--arc-w) var(--arc-h) at 50% var(--arc-y),
|
||||
#4b7bec 0 var(--arc-stop),
|
||||
transparent calc(var(--arc-stop) + 1%));
|
||||
}
|
||||
|
||||
.tirada-card.selected:hover {
|
||||
/* evita que :hover base anule la escala */
|
||||
transform: scaleY(var(--sel-scale-y));
|
||||
}
|
||||
|
||||
.tirada-card.selected .btn-select-tirada {
|
||||
background: var(--il-accent);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* texto en blanco dentro del círculo */
|
||||
.tirada-card.selected .title,
|
||||
.tirada-card.selected .price-big,
|
||||
.tirada-card.selected .per {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* ===== Línea inferior integrada (siempre visible en NO seleccionadas) ===== */
|
||||
.tirada-card:not(.selected)::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 1px;
|
||||
right: 1px;
|
||||
bottom: 1px;
|
||||
/* dentro del borde */
|
||||
height: 8px;
|
||||
background: var(--il-accent);
|
||||
border-bottom-left-radius: calc(var(--radius) - 1px);
|
||||
border-bottom-right-radius: calc(var(--radius) - 1px);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.tirada-card.selected::after {
|
||||
content: none;
|
||||
}
|
||||
|
||||
/* Oculta el radio */
|
||||
.tirada-card input[type="radio"] {
|
||||
display: none;
|
||||
}
|
||||
@ -1,4 +1,6 @@
|
||||
import imagen_presupuesto from "./imagen-presupuesto.js";
|
||||
import ServiceOptionCard from "./service-option-card.js";
|
||||
import TiradaCard from "./tirada-price-card.js";
|
||||
|
||||
class PresupuestoCliente {
|
||||
|
||||
@ -39,8 +41,24 @@ class PresupuestoCliente {
|
||||
cabezada: 'WHI',
|
||||
papelCubiertaId: 3,
|
||||
gramajeCubierta: 170,
|
||||
acabado: 1
|
||||
}
|
||||
acabado: 1,
|
||||
sobrecubierta: {
|
||||
activo: false,
|
||||
papelSobrecubiertaId: 2,
|
||||
gramajeSobrecubierta: 170,
|
||||
tamanioSolapasSobrecubierta: 80,
|
||||
acabado: 0
|
||||
},
|
||||
faja: {
|
||||
activo: false,
|
||||
papelFajaId: 2,
|
||||
gramajeFaja: 170,
|
||||
alto: 50,
|
||||
tamanioSolapasFaja: 80,
|
||||
acabado: 0
|
||||
}
|
||||
},
|
||||
selectedTirada: null,
|
||||
}
|
||||
|
||||
// pestaña datos generales
|
||||
@ -85,13 +103,44 @@ class PresupuestoCliente {
|
||||
this.guardasImpresas = $('#guardas-impresas');
|
||||
this.cabezada = $('#cabezada');
|
||||
this.divAcabadoCubierta = $('#div-acabado-cubierta');
|
||||
this.divSobrecubierta = $('#div-sobrecubierta');
|
||||
this.divFaja = $('#div-faja');
|
||||
this.acabadoSobrecubierta = $('#sobrecubierta-acabado');
|
||||
this.fajaSobrecubierta = $('#faja-acabado');
|
||||
this.sobrecubierta = $('#sobrecubierta');
|
||||
this.papelSobrecubierta = $('#papel-sobrecubierta');
|
||||
this.solapasSobrecubierta = $('#tamanio-solapas-sobrecubierta');
|
||||
this.faja = $('#faja');
|
||||
this.papelFaja = $('#papel-faja');
|
||||
this.altoFaja = $('#alto-faja');
|
||||
this.solapasFaja = $('#tamanio-solapas-faja');
|
||||
this.acabadoFaja = $('#faja-acabado');
|
||||
|
||||
// seleccion tirada
|
||||
this.divTiradas = $('#div-tiradas');
|
||||
this.divTiradasError = $('#div-tiradas-error');
|
||||
|
||||
// pestaña extras
|
||||
this.divExtras = $('#div-extras');
|
||||
}
|
||||
|
||||
init() {
|
||||
|
||||
const stored = sessionStorage.getItem("formData");
|
||||
|
||||
this.#initDatosGenerales();
|
||||
this.#initInterior();
|
||||
this.#initCubierta();
|
||||
|
||||
if (stored) {
|
||||
this.formData = JSON.parse(stored);
|
||||
this.#loadDatosGeneralesData();
|
||||
this.#loadCubiertaData();
|
||||
}
|
||||
|
||||
|
||||
this.#initInterior();
|
||||
this.#initSeleccionTirada();
|
||||
this.#initExtras();
|
||||
|
||||
$(document).on('change', 'input[min][max]', function () {
|
||||
const $input = $(this);
|
||||
@ -108,11 +157,10 @@ class PresupuestoCliente {
|
||||
}
|
||||
});
|
||||
|
||||
const stored = sessionStorage.getItem("formData");
|
||||
if (stored) {
|
||||
this.formData = JSON.parse(stored);
|
||||
this.#loadDatosGeneralesData();
|
||||
}
|
||||
$('.custom-nav .nav-link').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation(); // frena el handler de Bootstrap
|
||||
});
|
||||
}
|
||||
|
||||
#cacheFormData() {
|
||||
@ -122,22 +170,45 @@ class PresupuestoCliente {
|
||||
#changeTab(idContenidoTab) {
|
||||
const tabButton = document.querySelector(`[data-bs-target="#${idContenidoTab}"]`);
|
||||
if (tabButton) {
|
||||
const tab = new bootstrap.Tab(tabButton);
|
||||
tab.show();
|
||||
bootstrap.Tab.getOrCreateInstance(tabButton).show();
|
||||
}
|
||||
}
|
||||
|
||||
#getPresupuestoData() {
|
||||
return {
|
||||
let data = {
|
||||
...this.#getDatosGeneralesData(),
|
||||
...this.#getInteriorData(),
|
||||
...this.#getCubiertaData()
|
||||
...this.#getCubiertaData(),
|
||||
selectedTirada: this.formData.selectedTirada
|
||||
};
|
||||
|
||||
const sobrecubierta = data.sobrecubierta;
|
||||
const faja = data.faja;
|
||||
|
||||
delete data.sobrecubierta;
|
||||
delete data.faja;
|
||||
data = {
|
||||
...data,
|
||||
sobrecubierta: sobrecubierta.activo,
|
||||
papelSobrecubiertaId: sobrecubierta.papelSobrecubiertaId,
|
||||
gramajeSobrecubierta: sobrecubierta.gramajeSobrecubierta,
|
||||
tamanioSolapasSobrecubierta: sobrecubierta.tamanioSolapasSobrecubierta,
|
||||
acabadoSobrecubierta: sobrecubierta.acabado,
|
||||
faja: faja.activo,
|
||||
papelFajaId: faja.papelFajaId,
|
||||
gramajeFaja: faja.gramajeFaja,
|
||||
altoFaja: faja.alto,
|
||||
tamanioSolapasFaja: faja.tamanioSolapasFaja,
|
||||
acabadoFaja: faja.acabado
|
||||
}
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
#addGramaje(contenedor, gramaje, name) {
|
||||
#addGramaje(contenedor, id_base, gramaje, name) {
|
||||
|
||||
const id = `gramaje-${gramaje}`;
|
||||
const id = `${id_base}-${gramaje}`;
|
||||
|
||||
// Crear input
|
||||
const input = document.createElement('input');
|
||||
@ -178,6 +249,7 @@ class PresupuestoCliente {
|
||||
else {
|
||||
this.divPosicionPaginasColor.removeClass('d-none');
|
||||
}
|
||||
this.paginas = parseInt(this.paginasNegro.val()) + parseInt(this.paginasColor.val());
|
||||
this.#updateTipoEncuadernacion();
|
||||
});
|
||||
|
||||
@ -241,6 +313,8 @@ class PresupuestoCliente {
|
||||
|
||||
this.datos_generales_alert.addClass('d-none');
|
||||
|
||||
$('.alto-faja-max').text(`max: ${this.formData.datosGenerales.alto} mm`);
|
||||
|
||||
this.#loadInteriorData(data);
|
||||
|
||||
const interiorData = this.#getInteriorData();
|
||||
@ -541,6 +615,8 @@ class PresupuestoCliente {
|
||||
});
|
||||
|
||||
this.divAcabadoCubierta.empty();
|
||||
this.acabadoSobrecubierta.empty();
|
||||
this.fajaSobrecubierta.empty();
|
||||
for (const opcion of data.opciones_acabados_cubierta) {
|
||||
const item = `
|
||||
<input type="radio" class="btn-check acabado-cubierta-check" id="acabado-cubierta-${opcion['sk-id']}" name="acabado-cubierta" sk-id="${opcion['sk-id']}">
|
||||
@ -549,16 +625,20 @@ class PresupuestoCliente {
|
||||
</label>
|
||||
`;
|
||||
this.divAcabadoCubierta.append(item);
|
||||
this.acabadoSobrecubierta.append(new Option(opcion.name, opcion['sk-id']));
|
||||
this.fajaSobrecubierta.append(new Option(opcion.name, opcion['sk-id']));
|
||||
};
|
||||
|
||||
$(`input[type="radio"][name="acabado-cubierta"][sk-id="${this.formData.cubierta.acabado}"]`).prop('checked', true);
|
||||
this.acabadoSobrecubierta.val(this.formData.cubierta.sobrecubierta.acabado);
|
||||
this.fajaSobrecubierta.val(this.formData.cubierta.faja.acabado);
|
||||
|
||||
this.#loadCubiertaData(data);
|
||||
this.#loadCubiertaData();
|
||||
|
||||
this.#changeTab('pills-cover');
|
||||
|
||||
const dataInterior = this.#getInteriorData();
|
||||
this.#updateInteriorData(dataInterior);
|
||||
const dataCubierta = this.#getCubiertaData();
|
||||
this.#updateCubiertaData(dataCubierta);
|
||||
this.#cacheFormData();
|
||||
|
||||
}
|
||||
@ -628,13 +708,13 @@ class PresupuestoCliente {
|
||||
|
||||
for (let i = 0; i < gramajes.length; i++) {
|
||||
const gramaje = gramajes[i];
|
||||
this.#addGramaje(this.divGramajeInterior, gramaje, 'gramaje-interior');
|
||||
this.#addGramaje(this.divGramajeInterior, 'gramaje-interior', gramaje, 'gramaje-interior');
|
||||
|
||||
// Seleccionar el gramaje por defecto
|
||||
if (this.formData.interior.gramajeInterior === '' && i === 0) {
|
||||
$(`#gramaje-${gramaje}`).prop('checked', true);
|
||||
$(`#gramaje-interior-${gramaje}`).prop('checked', true);
|
||||
} else if (this.formData.interior.gramajeInterior == gramaje) {
|
||||
$(`#gramaje-${gramaje}`).prop('checked', true);
|
||||
$(`#gramaje-interior-${gramaje}`).prop('checked', true);
|
||||
}
|
||||
}
|
||||
if (this.divGramajeInterior.find('input[type="radio"]:checked').length === 0) {
|
||||
@ -763,6 +843,15 @@ class PresupuestoCliente {
|
||||
});
|
||||
});
|
||||
|
||||
$(document).on('click', '.gramaje-cubierta', (e) => {
|
||||
|
||||
const inputId = $(e.currentTarget).attr('for');
|
||||
const gramaje = parseInt($('#' + inputId).data('gramaje'));
|
||||
this.formData.cubierta.gramajeCubierta = gramaje;
|
||||
this.#cacheFormData();
|
||||
|
||||
});
|
||||
|
||||
$(document).on('change', '.datos-cubierta', (e) => {
|
||||
|
||||
const dataToStore = this.#getCubiertaData();
|
||||
@ -775,21 +864,63 @@ class PresupuestoCliente {
|
||||
this.formData.cubierta.acabado = parseInt($(e.currentTarget).attr('sk-id')) || 1;
|
||||
this.#cacheFormData();
|
||||
});
|
||||
|
||||
$('.btn-change-tab-cubierta').on('click', () => {
|
||||
this.#changeTab('pills-inside');
|
||||
/*const data = this.#getPresupuestoData();
|
||||
|
||||
$(document).on('click', '.custom-toggle', (e) => {
|
||||
|
||||
const $target = $(e.currentTarget);
|
||||
if ($target.hasClass('active')) {
|
||||
if ($target.attr('id') === 'sobrecubierta') {
|
||||
this.divSobrecubierta.removeClass('d-none');
|
||||
}
|
||||
else if ($target.attr('id') === 'faja') {
|
||||
this.divFaja.removeClass('d-none');
|
||||
}
|
||||
} else {
|
||||
if ($target.attr('id') === 'sobrecubierta') {
|
||||
this.divSobrecubierta.addClass('d-none');
|
||||
}
|
||||
else if ($target.attr('id') === 'faja') {
|
||||
this.divFaja.addClass('d-none');
|
||||
}
|
||||
}
|
||||
const dataToStore = this.#getCubiertaData();
|
||||
this.#updateCubiertaData(dataToStore);
|
||||
this.#cacheFormData();
|
||||
});
|
||||
|
||||
$('.btn-change-tab-cubierta').on('click', (e) => {
|
||||
|
||||
const data = this.#getPresupuestoData();
|
||||
const id = e.currentTarget.id;
|
||||
$.ajax({
|
||||
url: '/presupuesto/public/validar/cubierta',
|
||||
type: 'POST',
|
||||
data: data,
|
||||
url: '/presupuesto/public/validar/cubierta',
|
||||
type: 'POST',
|
||||
data: data,
|
||||
success: (data) => {
|
||||
this.#changeTab('pills-inside');
|
||||
if (id === 'btn-prev-cubierta') {
|
||||
this.#changeTab('pills-inside');
|
||||
}
|
||||
else {
|
||||
$('#btn-next-seleccion-tirada').removeClass('d-none');
|
||||
this.#loadSeleccionTiradaData(data);
|
||||
this.#changeTab('pills-seleccion-tirada');
|
||||
}
|
||||
},
|
||||
error: (xhr, status, error) => {
|
||||
console.error("Error al validar los datos de cubierta: ", xhr.responseText);
|
||||
if (id === 'btn-prev-cubierta') {
|
||||
this.#changeTab('pills-inside');
|
||||
return;
|
||||
}
|
||||
this.divTiradas.empty();
|
||||
this.divTiradasError.empty();
|
||||
this.divTiradas.addClass('d-none');
|
||||
this.divTiradasError.removeClass('d-none');
|
||||
$('#btn-next-seleccion-tirada').addClass('d-none');
|
||||
this.divTiradasError.append('<div class="alert alert-danger" role="alert">' +
|
||||
'<h4>' + xhr.responseText + '</h4></div>');
|
||||
this.#changeTab('pills-seleccion-tirada');
|
||||
}
|
||||
});*/
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -833,20 +964,7 @@ class PresupuestoCliente {
|
||||
this.divPapelCubierta.find('.image-container').first().data('sk-id') || 3;
|
||||
}
|
||||
|
||||
const gramajesCubierta = data.opciones_gramaje_cubierta;
|
||||
for (let i = 0; i < gramajesCubierta.length; i++) {
|
||||
const gramaje = gramajesCubierta[i];
|
||||
this.#addGramaje(this.divGramajeCubierta, gramaje, 'gramaje-cubierta');
|
||||
|
||||
if (this.formData.cubierta.gramajeCubierta === '' && i === 0) {
|
||||
$(`#gramaje-${gramaje}`).prop('checked', true);
|
||||
} else if (this.formData.cubierta.gramajeCubierta == gramaje) {
|
||||
$(`#gramaje-${gramaje}`).prop('checked', true);
|
||||
}
|
||||
}
|
||||
if (this.divGramajeCubierta.find('input[type="radio"]:checked').length === 0) {
|
||||
this.divGramajeCubierta.find('input[type="radio"]').first().prop('checked', true);
|
||||
}
|
||||
this.#addGramajesCubierta(data.opciones_gramaje_cubierta);
|
||||
|
||||
const dataToStore = this.#getCubiertaData();
|
||||
this.#updateCubiertaData(dataToStore);
|
||||
@ -870,9 +988,20 @@ class PresupuestoCliente {
|
||||
const guardasGramaje = parseInt($('#papel-guardas option:selected').data('gramaje')) || 170;
|
||||
const guardasImpresas = parseInt(this.guardasImpresas) || 0;
|
||||
const cabezada = this.cabezada.val() || 'WHI';
|
||||
const papelCubiertaId = $('#div-papel-cubierta .image-container.selected').data('sk-id') || 3;
|
||||
const gramajeCubierta = $('input[name="gramaje-cubierta"]:checked').data('gramaje') || 240;
|
||||
const papelCubiertaId = $('#div-papel-cubierta .image-container.selected').data('sk-id') || this.formData.cubierta.papelCubiertaId || 3;
|
||||
const gramajeCubierta = $('input[name="gramaje-cubierta"]:checked').data('gramaje') || this.formData.cubierta.gramajeCubierta || 170;
|
||||
const acabado = parseInt($(`input[name="acabado-cubierta"]:checked`).attr('sk-id')) || 1;
|
||||
const sobrecubierta = this.sobrecubierta.hasClass('active');
|
||||
const papelSobrecubiertaId = $('#papel-sobrecubierta option:selected').data('papel-id') || 2;
|
||||
const gramajeSobrecubierta = parseInt($('#papel-sobrecubierta option:selected').data('gramaje')) || 170;
|
||||
const solapasSobrecubierta = parseInt(this.solapasSobrecubierta.val()) || 0;
|
||||
const acabadoSobrecubierta = this.acabadoSobrecubierta.val() || 0;
|
||||
const faja = this.faja.hasClass('active');
|
||||
const papelFajaId = $('#papel-faja option:selected').data('papel-id') || 2;
|
||||
const gramajeFaja = parseInt($('#papel-faja option:selected').data('gramaje')) || 170;
|
||||
const fajaAlto = parseInt(this.altoFaja.val()) || 50;
|
||||
const solapasFaja = parseInt(this.solapasFaja.val()) || 0;
|
||||
const acabadoFaja = this.acabadoFaja.val() || 0;
|
||||
|
||||
return {
|
||||
tipoCubierta: tipoCubierta,
|
||||
@ -885,7 +1014,22 @@ class PresupuestoCliente {
|
||||
cabezada: cabezada,
|
||||
papelCubiertaId: papelCubiertaId,
|
||||
gramajeCubierta: gramajeCubierta,
|
||||
acabadado: acabado
|
||||
acabado: acabado,
|
||||
sobrecubierta: {
|
||||
activo: sobrecubierta,
|
||||
papelSobrecubiertaId: papelSobrecubiertaId,
|
||||
gramajeSobrecubierta: gramajeSobrecubierta,
|
||||
acabado: acabadoSobrecubierta,
|
||||
tamanioSolapasSobrecubierta: solapasSobrecubierta
|
||||
},
|
||||
faja: {
|
||||
activo: faja,
|
||||
papelFajaId: papelFajaId,
|
||||
gramajeFaja: gramajeFaja,
|
||||
alto: fajaAlto,
|
||||
acabado: acabadoFaja,
|
||||
tamanioSolapasFaja: solapasFaja
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -902,19 +1046,34 @@ class PresupuestoCliente {
|
||||
this.formData.cubierta.papelCubiertaId = data.papelCubiertaId;
|
||||
this.formData.cubierta.gramajeCubierta = data.gramajeCubierta;
|
||||
this.formData.cubierta.acabado = data.acabado;
|
||||
this.formData.cubierta.sobrecubierta = {
|
||||
activo: data.sobrecubierta.activo,
|
||||
papelSobrecubiertaId: data.sobrecubierta.papelSobrecubiertaId,
|
||||
gramajeSobrecubierta: data.sobrecubierta.gramajeSobrecubierta,
|
||||
tamanioSolapasSobrecubierta: data.sobrecubierta.tamanioSolapasSobrecubierta,
|
||||
acabado: data.sobrecubierta.acabado
|
||||
};
|
||||
this.formData.cubierta.faja = {
|
||||
activo: data.faja.activo,
|
||||
papelFajaId: data.faja.papelFajaId,
|
||||
gramajeFaja: data.faja.gramajeFaja,
|
||||
tamanioSolapasFaja: data.faja.tamanioSolapasFaja,
|
||||
acabado: data.faja.acabado,
|
||||
alto: data.faja.alto
|
||||
};
|
||||
}
|
||||
|
||||
#addGramajesCubierta(gramajes) {
|
||||
|
||||
for (let i = 0; i < gramajes.length; i++) {
|
||||
const gramaje = gramajes[i];
|
||||
this.#addGramaje(this.divGramajeCubierta, gramaje, 'gramaje-cubierta');
|
||||
this.#addGramaje(this.divGramajeCubierta, 'gramaje-cubierta', gramaje, 'gramaje-cubierta datos-cubierta');
|
||||
|
||||
// Seleccionar el gramaje por defecto
|
||||
if (this.formData.interior.gramajeCubierta === '' && i === 0) {
|
||||
$(`#gramaje-${gramaje}`).prop('checked', true);
|
||||
} else if (this.formData.interior.gramajeCubierta == gramaje) {
|
||||
$(`#gramaje-${gramaje}`).prop('checked', true);
|
||||
if (this.formData.cubierta.gramajeCubierta === '' && i === 0) {
|
||||
$(`#gramaje-cubierta-${gramaje}`).prop('checked', true);
|
||||
} else if (this.formData.cubierta.gramajeCubierta == gramaje) {
|
||||
$(`#gramaje-cubierta-${gramaje}`).prop('checked', true);
|
||||
}
|
||||
}
|
||||
if (this.divGramajeCubierta.find('input[type="radio"]:checked').length === 0) {
|
||||
@ -940,7 +1099,6 @@ class PresupuestoCliente {
|
||||
this.formData.cubierta.guardasGramaje + '"]').prop('selected', true).trigger('change');
|
||||
this.guardasImpresas.val(this.formData.cubierta.guardasImpresas);
|
||||
this.cabezada.val(this.formData.cubierta.cabezada);
|
||||
$(`input[type="radio"][name="acabado-cubierta"][sk-id="${this.formData.cubierta.acabado}"]`).prop('checked', true);
|
||||
}
|
||||
|
||||
$(`#${this.formData.cubierta.tipoCubierta}`).trigger('click');
|
||||
@ -958,13 +1116,153 @@ class PresupuestoCliente {
|
||||
}
|
||||
|
||||
this.carasImpresionCubierta.val(this.formData.cubierta.cubiertaCaras);
|
||||
$(`input[type="radio"][name="acabado-cubierta"][sk-id="${this.formData.cubierta.acabado}"]`).prop('checked', true);
|
||||
|
||||
if (this.formData.cubierta.sobrecubierta.activo) {
|
||||
this.sobrecubierta.addClass('active');
|
||||
this.divSobrecubierta.removeClass('d-none');
|
||||
}
|
||||
else {
|
||||
this.sobrecubierta.removeClass('active');
|
||||
this.divSobrecubierta.addClass('d-none');
|
||||
}
|
||||
$('#papel-sobrecubierta option[data-papel-id="' +
|
||||
this.formData.cubierta.sobrecubierta.papelSobrecubiertaId + '"][data-gramaje="' +
|
||||
this.formData.cubierta.sobrecubierta.gramajeSobrecubierta + '"]').prop('selected', true);
|
||||
this.solapasSobrecubierta.val(this.formData.cubierta.sobrecubierta.tamanioSolapasSobrecubierta);
|
||||
this.acabadoSobrecubierta.val(this.formData.cubierta.sobrecubierta.acabado);
|
||||
|
||||
|
||||
if (this.formData.cubierta.faja.activo) {
|
||||
this.faja.addClass('active');
|
||||
this.divFaja.removeClass('d-none');
|
||||
}
|
||||
else {
|
||||
this.faja.removeClass('active');
|
||||
this.divFaja.addClass('d-none');
|
||||
}
|
||||
$('#papel-faja option[data-papel-id="' +
|
||||
this.formData.cubierta.faja.papelFajaId + '"][data-gramaje="' +
|
||||
this.formData.cubierta.faja.gramajeFaja + '"]').prop('selected', true);
|
||||
this.solapasFaja.val(this.formData.cubierta.faja.tamanioSolapasFaja);
|
||||
this.altoFaja.val(this.formData.cubierta.faja.alto);
|
||||
this.acabadoFaja.val(this.formData.cubierta.faja.acabado);
|
||||
}
|
||||
/******************************
|
||||
* END CUBIERTA
|
||||
******************************/
|
||||
|
||||
|
||||
/******************************
|
||||
* SELECCION TIRADA
|
||||
******************************/
|
||||
#initSeleccionTirada() {
|
||||
|
||||
$(document).on('click', '.btn-change-tab-seleccion-tirada', (e) => {
|
||||
|
||||
const id = e.currentTarget.id;
|
||||
|
||||
if (id === 'btn-prev-seleccion-tirada') {
|
||||
this.#changeTab('pills-cover');
|
||||
} else {
|
||||
const data = this.#getPresupuestoData();
|
||||
const id = e.currentTarget.id;
|
||||
$.ajax({
|
||||
url: '/presupuesto/public/validar/seleccion-tirada',
|
||||
type: 'POST',
|
||||
data: data,
|
||||
success: (data) => {
|
||||
this.#loadExtrasData(data.servicios_extra);
|
||||
this.#changeTab('pills-extras');
|
||||
},
|
||||
error: (xhr, status, error) => {
|
||||
console.error("Error al validar los datos de selección de tirada: ", xhr.responseText);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
this.divTiradas.off('tirada:changed.cache') // por si re-bindeas
|
||||
.on('tirada:changed.cache', (e, detail) => {
|
||||
// detail = { id, name, unidades, precioUnidad, precioTotal }
|
||||
this.formData.selectedTirada = detail.unidades;
|
||||
this.#cacheFormData();
|
||||
});
|
||||
}
|
||||
|
||||
#loadSeleccionTiradaData(data) {
|
||||
|
||||
this.divTiradasError.addClass('d-none');
|
||||
this.divTiradas.empty();
|
||||
this.divTiradas.removeClass('d-none');
|
||||
this.divTiradas.removeClass('animate-fadeInUpBounce');
|
||||
|
||||
const labels = {
|
||||
perUnit: this.divTiradas.data('perUnit'),
|
||||
total: this.divTiradas.data('total'),
|
||||
select: this.divTiradas.data('select'),
|
||||
selected: this.divTiradas.data('selected'),
|
||||
units: this.divTiradas.data('units')
|
||||
};
|
||||
|
||||
this.divTiradas.addClass('animate-fadeInUpBounce');
|
||||
for (let i = 0; i < data.tiradas.length; i++) {
|
||||
const item = new TiradaCard({
|
||||
id: "tirada-" + data.tiradas[i],
|
||||
unidades: data.tiradas[i],
|
||||
precioUnidad: data.precios[i],
|
||||
precioTotal: data.precios[i] * data.tiradas[i],
|
||||
moneda: "€",
|
||||
labels: labels,
|
||||
selected: this.formData.selectedTirada == data.tiradas[i]
|
||||
});
|
||||
this.divTiradas.append(item.renderCol(this.divTiradas));
|
||||
}
|
||||
|
||||
if (this.divTiradas.find('.tirada-card input[type="radio"]:checked').length === 0) {
|
||||
this.divTiradas.find('.tirada-card input[type="radio"]').first().prop('checked', true).trigger('change');
|
||||
this.formData.selectedTirada = this.divTiradas.find('.tirada-card input[type="radio"]').first().data('unidades') || data.tiradas[0];
|
||||
}
|
||||
}
|
||||
/******************************
|
||||
* END SELECCION TIRADA
|
||||
******************************/
|
||||
|
||||
|
||||
|
||||
/******************************
|
||||
* EXTRAS
|
||||
******************************/
|
||||
#initExtras() {
|
||||
|
||||
$(document).on('click', '.btn-change-tab-extras', (e) => {
|
||||
|
||||
const id = e.currentTarget.id;
|
||||
|
||||
if (id === 'btn-prev-extras') {
|
||||
this.#changeTab('pills-seleccion-tirada');
|
||||
} else {
|
||||
//this.#changeTab('pills-finalizar');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#loadExtrasData(servicios) {
|
||||
|
||||
this.divExtras.empty();
|
||||
this.divExtras.removeClass('animate-fadeInUpBounce');
|
||||
|
||||
this.divExtras.addClass('animate-fadeInUpBounce');
|
||||
for (const extra of servicios) {
|
||||
const item = new ServiceOptionCard(extra);
|
||||
this.divExtras.append(item.render());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************
|
||||
* END EXTRAS
|
||||
******************************/
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,46 @@
|
||||
class ServiceOptionCard {
|
||||
|
||||
constructor({ id, title, description = '', price = '', priceUnit = '', checked = false, allowChange = true, ribbonText }) {
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.description = description ? description : ' ';
|
||||
this.price = price;
|
||||
this.priceUnit = priceUnit;
|
||||
this.checked = checked;
|
||||
this.allowChange = !(String(allowChange).toLowerCase() === "false");
|
||||
this.ribbonText = ribbonText;
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const ribbonHtml = this.ribbonText
|
||||
? `<div class="ribbon-service"><span>${this.ribbonText}</span></div>`
|
||||
: '';
|
||||
const $card = $(`
|
||||
<div class="col-lg-2 col-md-3 col-sm-6 mb-3">
|
||||
<input type="checkbox" class="service-checkbox data-price=${this.price} btn-check-service" id="${this.id}" name="services[]" value="${this.id}" autocomplete="off" ${this.checked ? 'checked' : ''} />
|
||||
<label class="btn btn-outline-primary w-100 text-center py-3 px-2 d-flex flex-column align-items-center justify-content-center h-100" for="${this.id}">
|
||||
${ribbonHtml}
|
||||
<h5 class="service-title mb-1">${this.title}</h5>
|
||||
<p class="service-desc mb-1 small">${this.description}</p>
|
||||
<h4 class="service-price fw-semibold mt-2 h4 mb-0">${this.price} ${this.priceUnit}</h4>
|
||||
</label>
|
||||
</div>
|
||||
`);
|
||||
|
||||
const $checkbox = $card.find('input[type="checkbox"]');
|
||||
|
||||
if (!this.allowChange) {
|
||||
// Deshabilita el cambio de estado visual
|
||||
$checkbox.on('click', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
return $card;
|
||||
}
|
||||
}
|
||||
|
||||
export default ServiceOptionCard;
|
||||
@ -0,0 +1,123 @@
|
||||
// ===== Clase =====
|
||||
class TiradaCard {
|
||||
constructor({ id, titulo, unidades, precioUnidad, precioTotal, selected = false, moneda = '€', name = 'tirada',
|
||||
labels = {}, locale = (document.documentElement.lang || navigator.language || 'es-ES')
|
||||
}) {
|
||||
this.id = id;
|
||||
this.titulo = titulo;
|
||||
this.unidades = unidades;
|
||||
this.precioUnidad = precioUnidad;
|
||||
this.precioTotal = precioTotal;
|
||||
this.selected = selected;
|
||||
this.moneda = moneda;
|
||||
this.name = name;
|
||||
this.locale = locale;
|
||||
this.labels = Object.assign({
|
||||
perUnit: 'Precio por unidad',
|
||||
total: 'Total',
|
||||
select: 'Seleccionar tirada',
|
||||
selected: 'Seleccionada',
|
||||
units: 'UNIDADES'
|
||||
}, labels);
|
||||
this.$container = null; // se establece al renderizar
|
||||
}
|
||||
|
||||
#formatMoneyES(value, decimals = 2) {
|
||||
return new Intl.NumberFormat(this.locale, {
|
||||
minimumFractionDigits: decimals,
|
||||
maximumFractionDigits: decimals
|
||||
}).format(Number(value));
|
||||
}
|
||||
|
||||
#title() {
|
||||
if (this.titulo) return this.titulo;
|
||||
if (this.unidades != null) return `${this.unidades} ${this.labels.units}`;
|
||||
return '';
|
||||
}
|
||||
|
||||
// pásale el contenedor donde van todas las tarjetas de este grupo
|
||||
renderCol($container) {
|
||||
this.$container = $container ? $($container) : $(document.body);
|
||||
|
||||
const col = $(`
|
||||
<div class="col d-flex">
|
||||
<label class="tirada-card ${this.selected ? 'selected' : ''} w-100 h-100" for="tirada-${this.id}">
|
||||
<input type="radio" name="${this.name}" id="tirada-${this.id}" value="${this.unidades}" ${this.selected ? 'checked' : ''}>
|
||||
<div class="title">${this.#title()}</div>
|
||||
|
||||
<div class="per muted">${this.labels.perUnit}</div>
|
||||
<div class="price-big">${this.#formatMoneyES(this.precioUnidad, 4)} ${this.moneda}</div>
|
||||
|
||||
<div class="price-row">
|
||||
<div class="muted">${this.labels.total}</div>
|
||||
<div class="fw-bold">${this.#formatMoneyES(this.precioTotal, 2)} ${this.moneda}</div>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-select-tirada">${this.labels.select}</button>
|
||||
</label>
|
||||
</div>
|
||||
`);
|
||||
|
||||
// --- Delegación de eventos en el contenedor (una sola vez por grupo) ---
|
||||
const boundKey = `tirada-bound-${this.name}`;
|
||||
const groupName = this.name;
|
||||
const $group = this.$container;
|
||||
const labels = this.labels;
|
||||
|
||||
if (!$group.data(boundKey)) {
|
||||
$group.on('change', `input[type="radio"][name="${groupName}"]`, function () {
|
||||
// radios del grupo
|
||||
const $groupRadios = $group.find(`input[type="radio"][name="${groupName}"]`);
|
||||
|
||||
// resetear todas las tarjetas del grupo
|
||||
$groupRadios
|
||||
.closest('.tirada-card')
|
||||
.removeClass('selected')
|
||||
.find('.btn-select-tirada')
|
||||
.html(labels.select || 'Seleccionar tirada');
|
||||
|
||||
// marcar la tarjeta seleccionada y su botón
|
||||
const $card = $(this).closest('.tirada-card');
|
||||
$card.find('.btn-select-tirada')
|
||||
.html(labels.selected + ' <i class="mdi mdi-check-circle ms-1"></i>');
|
||||
$card.addClass('selected');
|
||||
|
||||
const $input = $(this);
|
||||
const detail = {
|
||||
id: $input.attr('id'),
|
||||
name: $input.attr('name'),
|
||||
unidades: Number($input.data('unidades') ?? $input.val()),
|
||||
precioUnidad: Number($input.data('precioUnidad')),
|
||||
precioTotal: Number($input.data('precioTotal'))
|
||||
};
|
||||
// jQuery: pasa 'detail' como segundo argumento del handler
|
||||
$group.trigger('tirada:changed', [detail]);
|
||||
|
||||
});
|
||||
|
||||
$group.data(boundKey, true);
|
||||
}
|
||||
|
||||
const $btnLocal = col.find('.btn-select-tirada');
|
||||
if (this.selected) {
|
||||
$btnLocal.html(labels.selected + ' <i class="mdi mdi-check-circle ms-1"></i>');
|
||||
}
|
||||
|
||||
// --- Comportamiento de la tarjeta/botón (local a esta tarjeta) ---
|
||||
const card = col.find('.tirada-card');
|
||||
|
||||
col.find('.btn-select-tirada').on('click', (e) => {
|
||||
e.preventDefault();
|
||||
card.find('input[type="radio"]').prop('checked', true).trigger('change');
|
||||
});
|
||||
|
||||
card.on('click', function (e) {
|
||||
if ($(e.target).is('.btn-select-tirada')) return;
|
||||
$(this).find('input[type="radio"]').prop('checked', true).trigger('change');
|
||||
});
|
||||
|
||||
return col;
|
||||
}
|
||||
}
|
||||
|
||||
export default TiradaCard;
|
||||
@ -46,7 +46,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="row justify-content-center mt-4 imagen-container-group tapa-blanda-options">
|
||||
<div class="col-auto">
|
||||
<div class="d-flex flex-wrap align-items-center gap-4 ">
|
||||
@ -93,7 +93,8 @@
|
||||
<div id="div-solapas-cubierta" class="d-none">
|
||||
<label for="tamanio-solapas-cubierta" class="form-label"
|
||||
th:text="#{presupuesto.tamanio-solapa}">Tamaño solapa</label>
|
||||
<input type="number" class="form-control form-control-sm solapas-presupuesto datos-cubierta"
|
||||
<input type="number"
|
||||
class="form-control form-control-sm solapas-presupuesto datos-cubierta"
|
||||
id="tamanio-solapas-cubierta" min="60" max="120" value="80" step="1">
|
||||
<div class="form-text">
|
||||
<p class="mb-0">min: 60 mm</p>
|
||||
@ -230,22 +231,174 @@
|
||||
<div class="hstack gap-2 justify-content-center flex-wrap mx-4">
|
||||
<p th:text="#{presupuesto.acabado-cubierta-aviso}"></p>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="div-acabado-cubierta" class="hstack gap-2 justify-content-center flex-wrap">
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- End Ribbon Shape -->
|
||||
|
||||
<!-- Ribbon Shape -->
|
||||
<div class="card ribbon-box border shadow-none mb-lg-0 material-shadow mt-4">
|
||||
<div class="card-body">
|
||||
<div class="ribbon ribbon-primary ribbon-shape" th:text="#{presupuesto.cubierta-extras}">Extras
|
||||
</div>
|
||||
<h5 class="fs-14 text-end" th:text="#{presupuesto.cubierta-extras-descripcion}">
|
||||
Opciones adicionales para la cubierta</h5>
|
||||
</div>
|
||||
|
||||
<div class="ribbon-content mt-4">
|
||||
|
||||
<div class="row justify-content-center mt-4">
|
||||
<div class="col-auto">
|
||||
<div class="d-flex flex-wrap align-items-center gap-4 ">
|
||||
|
||||
<button id="sobrecubierta" type="button" class="btn btn-outline-primary custom-toggle mb-4"
|
||||
data-bs-toggle="button">
|
||||
<span class="icon-on">
|
||||
<i class="ri-close-line align-bottom me-1"></i>
|
||||
<span th:text="#{presupuesto.sobrecubierta}"></span>
|
||||
</span>
|
||||
<span class="icon-off">
|
||||
<i class="ri-add-line align-bottom me-1"></i>
|
||||
<span th:text="#{presupuesto.sobrecubierta}"></span>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<div id="div-sobrecubierta" class="d-flex flex-wrap d-none align-items-start gap-3">
|
||||
<div class="d-flex flex-column me-2">
|
||||
<label for="papel-sobrecubierta" class="form-label"
|
||||
th:text="#{presupuesto.sobrecubierta-papel}">Papel</label>
|
||||
<select class="form-select select2 datos-cubierta w-auto" id="papel-sobrecubierta">
|
||||
<optgroup th:label="#{presupuesto.estucado}">
|
||||
<option selected value="2" data-papel-id="2" data-gramaje="170"
|
||||
th:text="#{presupuesto.estucado-mate} + ' 170 gr'">Estucado mate 170 gr
|
||||
</option>
|
||||
</optgroup>
|
||||
<optgroup th:label="#{presupuesto.verjurado}">
|
||||
<option value="1" data-papel-id="18" data-gramaje="160"
|
||||
th:text="#{presupuesto.verjurado-blanco-natural} + ' 160 gr'">Verjurado blanco natural 160 gr
|
||||
170 gr
|
||||
</option>
|
||||
<option value="2" data-papel-id="9" data-gramaje="160"
|
||||
th:text="#{presupuesto.verjurado-ahuesado} + ' 160 gr'">Verjurado ahuesado 160 gr
|
||||
</option>
|
||||
</optgroup>
|
||||
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column me-2">
|
||||
<label for="tamanio-solapas-sobrecubierta" class="form-label"
|
||||
th:text="#{presupuesto.sobrecubierta-solapas}">Tamaño solapas sobrecubierta</label>
|
||||
<input type="number" class="form-control datos-cubierta w-auto"
|
||||
id="tamanio-solapas-sobrecubierta" min="60" max="120" value="80" step="1">
|
||||
<div class="form-text">
|
||||
<p class="mb-0">min: 60 mm</p>
|
||||
<p class="max-solapa-text">max: 120 mm</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column me-2">
|
||||
<label for="sobrecubierta-acabado" class="form-label"
|
||||
th:text="#{presupuesto.acabado}">Acabado</label>
|
||||
<select class="form-select select2 datos-cubierta w-auto" id="sobrecubierta-acabado">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row justify-content-center mt-4">
|
||||
<div class="col-auto">
|
||||
<div class="d-flex flex-wrap align-items-center gap-4 ">
|
||||
|
||||
<button id="faja" type="button" class="btn btn-outline-primary custom-toggle mb-4"
|
||||
data-bs-toggle="button">
|
||||
<span class="icon-on">
|
||||
<i class="ri-close-line align-bottom me-1"></i>
|
||||
<span th:text="#{presupuesto.faja}"></span>
|
||||
</span>
|
||||
<span class="icon-off">
|
||||
<i class="ri-add-line align-bottom me-1"></i>
|
||||
<span th:text="#{presupuesto.faja}"></span>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<div id="div-faja" class="d-flex flex-wrap d-none align-items-start gap-3">
|
||||
<div class="d-flex flex-column me-2">
|
||||
<label for="papel-faja" class="form-label"
|
||||
th:text="#{presupuesto.faja-papel}">Papel</label>
|
||||
<select class="form-select select2 datos-cubierta w-auto" id="papel-faja">
|
||||
<optgroup th:label="#{presupuesto.estucado}">
|
||||
<option selected value="2" data-papel-id="2" data-gramaje="170"
|
||||
th:text="#{presupuesto.estucado-mate} + ' 170 gr'">Estucado mate 170 gr
|
||||
</option>
|
||||
</optgroup>
|
||||
<optgroup th:label="#{presupuesto.verjurado}">
|
||||
<option value="1" data-papel-id="18" data-gramaje="160"
|
||||
th:text="#{presupuesto.verjurado-blanco-natural} + ' 160 gr'">Verjurado blanco natural 160 gr
|
||||
170 gr
|
||||
</option>
|
||||
<option value="2" data-papel-id="9" data-gramaje="160"
|
||||
th:text="#{presupuesto.verjurado-ahuesado} + ' 160 gr'">Verjurado ahuesado 160 gr
|
||||
</option>
|
||||
</optgroup>
|
||||
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column me-2">
|
||||
<label for="alto-faja" class="form-label"
|
||||
th:text="#{presupuesto.faja-alto}">Alto faja</label>
|
||||
<input type="number" class="form-control datos-cubierta w-auto"
|
||||
id="alto-faja" min="50" max="120" value="80" step="1">
|
||||
<div class="form-text">
|
||||
<p class="mb-0">min: 50 mm</p>
|
||||
<p class="alto-faja-max">max: 120 mm</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column me-2">
|
||||
<label for="tamanio-solapas-faja" class="form-label"
|
||||
th:text="#{presupuesto.faja-solapas}">Tamaño solapas faja</label>
|
||||
<input type="number" class="form-control datos-cubierta w-auto"
|
||||
id="tamanio-solapas-faja" min="60" max="120" value="80" step="1">
|
||||
<div class="form-text">
|
||||
<p class="mb-0">min: 60 mm</p>
|
||||
<p class="max-solapa-text">max: 120 mm</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column me-2">
|
||||
<label for="faja-acabado" class="form-label"
|
||||
th:text="#{presupuesto.acabado}">Acabado</label>
|
||||
<select class="form-select select2 datos-cubierta w-auto" id="faja-acabado">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- End Ribbon Shape -->
|
||||
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mt-4 w-100">
|
||||
<button id="btn-prev-cubierta" type="button" class="btn btn-light d-flex align-items-center btn-change-tab-cubierta">
|
||||
<button id="btn-prev-cubierta" type="button"
|
||||
class="btn btn-light d-flex align-items-center btn-change-tab-cubierta">
|
||||
<i class=" ri-arrow-left-circle-line label-icon align-middle fs-16 me-2"></i>
|
||||
<span th:text="#{presupuesto.volver-interior}">Volver a interior</span>
|
||||
</button>
|
||||
<button id="btn-next-cubierta" type="button" class="btn btn-primary d-flex align-items-center btn-change-tab-cubierta">
|
||||
<span th:text="#{presupuesto.continuar-extras-libro}">Continuar a extras del libro</span>
|
||||
<button id="btn-next-cubierta" type="button"
|
||||
class="btn btn-primary d-flex align-items-center btn-change-tab-cubierta">
|
||||
<span th:text="#{presupuesto.continuar-seleccion-tirada}">Continuar a selección de tirada</span>
|
||||
<i class="ri-arrow-right-circle-line fs-16 ms-2"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@ -156,7 +156,7 @@
|
||||
</div>
|
||||
|
||||
<div id="div-posicion-paginas-color" class="row justify-content-center">
|
||||
<div class="col-sm-9">
|
||||
<div class="col-sm-6">
|
||||
<label for="posicionPaginasColor" class="form-label" th:text="#{presupuesto.paginas-posicion}">
|
||||
Posición páginas color
|
||||
</label>
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
<div class="animate-fadeInUpBounce">
|
||||
|
||||
<!-- Ribbon Shape -->
|
||||
<div class="card ribbon-box border shadow-none mb-lg-0 material-shadow">
|
||||
<div class="card-body">
|
||||
<div class="ribbon ribbon-primary ribbon-shape" th:text="#{presupuesto.extras}">Extras
|
||||
</div>
|
||||
<h5 class="fs-14 text-end" th:text="#{presupuesto.extras-descripcion}">Seleccione los extras
|
||||
que desea añadir a su presupuesto.</h5>
|
||||
</div>
|
||||
|
||||
<div class="ribbon-content mt-4">
|
||||
<div id="div-extras" class="hstack gap-2 justify-content-center flex-wrap">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- End Ribbon Shape -->
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mt-4 w-100">
|
||||
<button id="btn-prev-extras" type="button"
|
||||
class="btn btn-light d-flex align-items-center btn-change-tab-extras">
|
||||
<i class=" ri-arrow-left-circle-line label-icon align-middle fs-16 me-2"></i>
|
||||
<span th:text="#{presupuesto.volver-seleccion-tirada}">Volver a selección de tirada</span>
|
||||
</button>
|
||||
<button id="btn-next-extras" type="button"
|
||||
class="btn btn-primary d-flex align-items-center btn-change-tab-extras">
|
||||
<span><b th:text="#{presupuesto.calcular-presupuesto}">Calcular presupuesto</b></span>
|
||||
<i class="ri-arrow-right-circle-line fs-16 ms-2"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -0,0 +1,41 @@
|
||||
<div class="animate-fadeInUpBounce">
|
||||
|
||||
<!-- Ribbon Shape -->
|
||||
<div class="card ribbon-box border shadow-none mb-lg-0 material-shadow">
|
||||
<div class="card-body">
|
||||
<div class="ribbon ribbon-primary ribbon-shape" th:text="#{presupuesto.seleccion-tirada}">Seleccion de
|
||||
tirada
|
||||
</div>
|
||||
<h5 class="fs-14 text-end" th:text="#{presupuesto.seleccion-tirada-descripcion}">Seleccione la tirada
|
||||
deseada</h5>
|
||||
</div>
|
||||
|
||||
<div class="ribbon-content mt-4">
|
||||
<div id="div-tiradas-error"
|
||||
class="d-flex justify-content-center mt-4 w-100 d-none">
|
||||
|
||||
</div>
|
||||
<div id="div-tiradas"
|
||||
class="row row-cols-1 row-cols-sm-2 row-cols-lg-4 g-4 justify-content-center align-items-stretch mx-auto mb-4"
|
||||
style="max-width:1120px" th:data-per-unit="#{presupuesto.precio-unidad}"
|
||||
th:data-total="#{presupuesto.total}" th:data-select="#{presupuesto.seleccionar-tirada}"
|
||||
th:data-selected="#{presupuesto.tirada-seleccionada}" th:data-units="#{presupuesto.unidades}">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- End Ribbon Shape -->
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mt-4 w-100">
|
||||
<button id="btn-prev-seleccion-tirada" type="button"
|
||||
class="btn btn-light d-flex align-items-center btn-change-tab-seleccion-tirada">
|
||||
<i class=" ri-arrow-left-circle-line label-icon align-middle fs-16 me-2"></i>
|
||||
<span th:text="#{presupuesto.volver-cubierta}">Volver a diseño de cubierta</span>
|
||||
</button>
|
||||
<button id="btn-next-seleccion-tirada" type="button"
|
||||
class="btn btn-primary d-flex align-items-center btn-change-tab-seleccion-tirada">
|
||||
<span><b th:text="#{presupuesto.continuar-extras-libro}">Continuar a extras del libro</b></span>
|
||||
<i class="ri-arrow-right-circle-line fs-16 ms-2"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -0,0 +1,74 @@
|
||||
<div class="col-xl-4">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="d-flex">
|
||||
<div class="flex-grow-1">
|
||||
<h5 th:text="#{presupuesto.resumen-presupuesto}">Resumen presupuesto</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive table-card">
|
||||
<table id="summary-interior" class="table table-responsive align-middle mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th th:text="#{presupuesto.resumen-libro}" scope="col" colspan="2">Libro</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="align-items-center">
|
||||
<span th:text="#{presupuesto.resumen-encuadernacion}"></span>
|
||||
</td>
|
||||
<td id="summary-formato" class="text-end">Fresado</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span th:text="#{presupuesto.formato}"></span>
|
||||
</td>
|
||||
<td id="summary-paginas" class="text-end">148 x 210 mm</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span th:text="#{presupuesto.paginas}"></span>
|
||||
</td>
|
||||
<td id="summary-paginas" class="text-end">148 x 210 mm</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="ps-3">
|
||||
<span class="ps-3" th:text="#{presupuesto.paginas-negro}"></span>
|
||||
</td>
|
||||
<td id="summary-paginas" class="text-end">148 x 210 mm</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="ps-3">
|
||||
<span class="ps-3" th:text="#{presupuesto.paginas-color}"></span>
|
||||
</td>
|
||||
<td id="summary-paginas" class="text-end">148 x 210 mm</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
<table id="summary-cubierta" class="table table-borderless align-middle mb-0 d-none">
|
||||
<thead class="table-light text-muted ">
|
||||
<tr>
|
||||
<th th:text="#{presupuesto.cubierta-libro}" scope="col" colspan="2">Cubierta del libro</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<p th:text="#{presupuesto.paginas}"></p>
|
||||
</td>
|
||||
<td id="summary-paginas2" class="text-end">148 x 210 mm</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- end card body -->
|
||||
</div>
|
||||
<!-- end card -->
|
||||
</div>
|
||||
<!-- end col -->
|
||||
@ -36,9 +36,18 @@
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link fs-15 p-3" id="pills-shipping-tab" data-bs-toggle="pill"
|
||||
data-bs-target="#pills-shipping" type="button" role="tab"
|
||||
aria-controls="pills-shipping" aria-selected="false">
|
||||
<button class="nav-link fs-15 p-3" id="pills-seleccion-tirada-tab"
|
||||
data-bs-toggle="pill" data-bs-target="#pills-seleccion-tirada" type="button"
|
||||
role="tab" aria-controls="pills-seleccion-tirada" aria-selected="false">
|
||||
<i
|
||||
class="ri-add-box-line fs-16 p-2 bg-soft-primary text-primary rounded-circle align-middle me-2"></i>
|
||||
<label th:text="#{presupuesto.seleccion-tirada}">Seleccion de tirada</label>
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link fs-15 p-3" id="pills-extras-tab" data-bs-toggle="pill"
|
||||
data-bs-target="#pills-extras" type="button" role="tab"
|
||||
aria-controls="pills-extras" aria-selected="false">
|
||||
<i
|
||||
class="ri-add-box-line fs-16 p-2 bg-soft-primary text-primary rounded-circle align-middle me-2"></i>
|
||||
<label th:text="#{presupuesto.extras}">Extras</label>
|
||||
@ -50,26 +59,45 @@
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane fade show active" id="pills-general-data" role="tabpanel"
|
||||
aria-labelledby="pills-general-data-tab">
|
||||
|
||||
<div th:include="~{imprimelibros/presupuestos/presupuestador-items/_datos-generales.html}"></div>
|
||||
|
||||
<div
|
||||
th:include="~{imprimelibros/presupuestos/presupuestador-items/_datos-generales.html}">
|
||||
</div>
|
||||
</div>
|
||||
<!-- end tab pane -->
|
||||
|
||||
<div class="tab-pane fade" id="pills-inside" role="tabpanel"
|
||||
aria-labelledby="pills-inside-tab">
|
||||
|
||||
<div th:include="~{imprimelibros/presupuestos/presupuestador-items/_interior.html}"></div>
|
||||
|
||||
<div th:include="~{imprimelibros/presupuestos/presupuestador-items/_interior.html}">
|
||||
</div>
|
||||
</div>
|
||||
<!-- end tab pane -->
|
||||
|
||||
<div class="tab-pane fade" id="pills-cover" role="tabpanel"
|
||||
aria-labelledby="pills-cover-tab">
|
||||
|
||||
<div th:include="~{imprimelibros/presupuestos/presupuestador-items/_cubierta.html}"></div>
|
||||
|
||||
<div th:include="~{imprimelibros/presupuestos/presupuestador-items/_cubierta.html}">
|
||||
</div>
|
||||
</div>
|
||||
<!-- end tab pane -->
|
||||
|
||||
<div class="tab-pane fade" id="pills-seleccion-tirada" role="tabpanel"
|
||||
aria-labelledby="pills-seleccion-tirada-tab">
|
||||
|
||||
<div
|
||||
th:include="~{imprimelibros/presupuestos/presupuestador-items/_seleccion-tirada.html}">
|
||||
</div>
|
||||
</div>
|
||||
<!-- end tab pane -->
|
||||
|
||||
<div class="tab-pane fade" id="pills-extras" role="tabpanel"
|
||||
aria-labelledby="pills-extras-tab">
|
||||
|
||||
<div th:include="~{imprimelibros/presupuestos/presupuestador-items/_extras.html}"></div>
|
||||
</div>
|
||||
<!-- end tab pane -->
|
||||
|
||||
|
||||
</div>
|
||||
<!-- end tab content -->
|
||||
</form>
|
||||
@ -80,103 +108,9 @@
|
||||
</div>
|
||||
<!-- end col -->
|
||||
|
||||
<!-- Order Summary -->
|
||||
<div class="col-xl-4">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="d-flex">
|
||||
<div class="flex-grow-1">
|
||||
<h5 class="card-title mb-0">Order Summary</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive table-card">
|
||||
<table class="table table-borderless align-middle mb-0">
|
||||
<thead class="table-light text-muted">
|
||||
<tr>
|
||||
<th style="width: 90px;" scope="col">Product</th>
|
||||
<th scope="col">Product Info</th>
|
||||
<th scope="col" class="text-end">Price</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="avatar-md bg-light rounded p-1">
|
||||
<img src="/assets/images/products/img-8.png" alt=""
|
||||
class="img-fluid d-block">
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<h5 class="fs-14"><a href="/apps-ecommerce-product-details"
|
||||
class="text-dark">Sweatshirt for Men (Pink)</a></h5>
|
||||
<p class="text-muted mb-0">$ 119.99 x 2</p>
|
||||
</td>
|
||||
<td class="text-end">$ 239.98</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="avatar-md bg-light rounded p-1">
|
||||
<img src="/assets/images/products/img-7.png" alt=""
|
||||
class="img-fluid d-block">
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<h5 class="fs-14"><a href="/apps-ecommerce-product-details"
|
||||
class="text-dark">Noise Evolve Smartwatch</a></h5>
|
||||
<p class="text-muted mb-0">$ 94.99 x 1</p>
|
||||
</td>
|
||||
<td class="text-end">$ 94.99</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="avatar-md bg-light rounded p-1">
|
||||
<img src="/assets/images/products/img-3.png" alt=""
|
||||
class="img-fluid d-block">
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<h5 class="fs-14"><a href="/apps-ecommerce-product-details"
|
||||
class="text-dark">350 ml Glass Grocery Container</a></h5>
|
||||
<p class="text-muted mb-0">$ 24.99 x 1</p>
|
||||
</td>
|
||||
<td class="text-end">$ 24.99</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fw-semibold" colspan="2">Sub Total :</td>
|
||||
<td class="fw-semibold text-end">$ 359.96</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">Discount <span class="text-muted">(VELZON15)</span> : </td>
|
||||
<td class="text-end">- $ 50.00</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">Shipping Charge :</td>
|
||||
<td class="text-end">$ 24.99</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">Estimated Tax (12%): </td>
|
||||
<td class="text-end">$ 18.20</td>
|
||||
</tr>
|
||||
<tr class="table-active">
|
||||
<th colspan="2">Total (USD) :</th>
|
||||
<td class="text-end">
|
||||
<span class="fw-semibold">
|
||||
$353.15
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!-- Summary -->
|
||||
<div th:replace="~{imprimelibros/presupuestos/presupuestador-items/_summary.html}"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- end card body -->
|
||||
</div>
|
||||
<!-- end card -->
|
||||
</div>
|
||||
<!-- end col -->
|
||||
</div>
|
||||
<!--end row-->
|
||||
</div>
|
||||
Reference in New Issue
Block a user