mirror of
https://git.imnavajas.es/jjimenez/erp-imprimelibros.git
synced 2026-01-13 00:48:49 +00:00
Merge branch 'mod/margenes-tirada' into 'main'
modificado los margenes por precio en lugar de por tirada y tipos See merge request jjimenez/erp-imprimelibros!11
This commit is contained in:
@ -5,18 +5,12 @@ import jakarta.transaction.Transactional;
|
|||||||
import org.springframework.context.MessageSource;
|
import org.springframework.context.MessageSource;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.RoundingMode;
|
|
||||||
import java.text.NumberFormat;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.imprimelibros.erp.presupuesto.classes.PresupuestoFormatter;
|
import com.imprimelibros.erp.presupuesto.classes.PresupuestoFormatter;
|
||||||
import com.imprimelibros.erp.presupuesto.dto.Presupuesto;
|
import com.imprimelibros.erp.presupuesto.dto.Presupuesto;
|
||||||
import com.imprimelibros.erp.common.Utils;
|
import com.imprimelibros.erp.common.Utils;
|
||||||
|
|||||||
@ -8,6 +8,8 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
import org.springframework.context.MessageSource;
|
import org.springframework.context.MessageSource;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@ -15,11 +17,17 @@ import org.springframework.stereotype.Component;
|
|||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.imprimelibros.erp.datatables.DataTablesRequest;
|
||||||
import com.imprimelibros.erp.presupuesto.classes.PresupuestoFormatter;
|
import com.imprimelibros.erp.presupuesto.classes.PresupuestoFormatter;
|
||||||
import com.imprimelibros.erp.presupuesto.dto.Presupuesto;
|
import com.imprimelibros.erp.presupuesto.dto.Presupuesto;
|
||||||
import com.imprimelibros.erp.presupuesto.maquetacion.MaquetacionMatrices;
|
import com.imprimelibros.erp.presupuesto.maquetacion.MaquetacionMatrices;
|
||||||
import com.imprimelibros.erp.presupuesto.marcapaginas.Marcapaginas;
|
import com.imprimelibros.erp.presupuesto.marcapaginas.Marcapaginas;
|
||||||
|
|
||||||
|
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||||
|
import jakarta.persistence.criteria.Path;
|
||||||
|
import jakarta.persistence.criteria.Predicate;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class Utils {
|
public class Utils {
|
||||||
|
|
||||||
@ -42,6 +50,55 @@ public class Utils {
|
|||||||
return currencyFormatter.format(amount);
|
return currencyFormatter.format(amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String formatNumber(BigDecimal amount, Locale locale) {
|
||||||
|
NumberFormat numberFormatter = NumberFormat.getNumberInstance(locale);
|
||||||
|
return numberFormatter.format(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String formatNumber(Double amount, Locale locale) {
|
||||||
|
NumberFormat numberFormatter = NumberFormat.getNumberInstance(locale);
|
||||||
|
return numberFormatter.format(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Optional<BiFunction<Path<BigDecimal>, CriteriaBuilder, Predicate>> parseNumericFilter(
|
||||||
|
DataTablesRequest dt, String colName, Locale locale) {
|
||||||
|
String raw = dt.getColumnSearch(colName); // usa el "name" del DataTable (snake_case)
|
||||||
|
if (raw == null || raw.isBlank())
|
||||||
|
return Optional.empty();
|
||||||
|
|
||||||
|
String s = raw.trim();
|
||||||
|
// normaliza número con coma o punto
|
||||||
|
Function<String, BigDecimal> toBig = x -> {
|
||||||
|
String t = x.replace(".", "").replace(",", "."); // 1.234,56 -> 1234.56
|
||||||
|
return new BigDecimal(t);
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (s.matches("(?i)^>=?\\s*[-\\d.,]+$")) {
|
||||||
|
BigDecimal v = toBig.apply(s.replace(">=", "").replace(">", "").trim());
|
||||||
|
return Optional.of((path, cb) -> cb.greaterThanOrEqualTo(path, v));
|
||||||
|
}
|
||||||
|
if (s.matches("(?i)^<=?\\s*[-\\d.,]+$")) {
|
||||||
|
BigDecimal v = toBig.apply(s.replace("<=", "").replace("<", "").trim());
|
||||||
|
return Optional.of((path, cb) -> cb.lessThanOrEqualTo(path, v));
|
||||||
|
}
|
||||||
|
if (s.contains("-")) { // rango "a-b"
|
||||||
|
String[] p = s.split("-");
|
||||||
|
if (p.length == 2) {
|
||||||
|
BigDecimal a = toBig.apply(p[0].trim());
|
||||||
|
BigDecimal b = toBig.apply(p[1].trim());
|
||||||
|
BigDecimal min = a.min(b), max = a.max(b);
|
||||||
|
return Optional.of((path, cb) -> cb.between(path, min, max));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// exacto/like numérico
|
||||||
|
BigDecimal v = toBig.apply(s);
|
||||||
|
return Optional.of((path, cb) -> cb.equal(path, v));
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Map<String, Object> getTextoPresupuesto(Presupuesto presupuesto, Locale locale) {
|
public Map<String, Object> getTextoPresupuesto(Presupuesto presupuesto, Locale locale) {
|
||||||
|
|
||||||
Map<String, Object> resumen = new HashMap<>();
|
Map<String, Object> resumen = new HashMap<>();
|
||||||
|
|||||||
@ -1,182 +1,126 @@
|
|||||||
package com.imprimelibros.erp.configuracion.margenes_presupuestos;
|
package com.imprimelibros.erp.configuracion.margenes_presupuestos;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import jakarta.validation.constraints.Max;
|
|
||||||
import jakarta.validation.constraints.Min;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
import org.hibernate.annotations.SQLDelete;
|
import org.hibernate.annotations.SQLDelete;
|
||||||
import org.hibernate.annotations.SQLRestriction;
|
import org.hibernate.annotations.SQLRestriction;
|
||||||
|
|
||||||
import com.imprimelibros.erp.presupuesto.dto.Presupuesto.TipoCubierta;
|
|
||||||
import com.imprimelibros.erp.presupuesto.dto.Presupuesto.TipoEncuadernacion;
|
|
||||||
import com.imprimelibros.erp.shared.validation.NoRangeOverlap;
|
import com.imprimelibros.erp.shared.validation.NoRangeOverlap;
|
||||||
|
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "margenes_presupuesto")
|
||||||
|
@SQLDelete(sql = "UPDATE margenes_presupuesto SET deleted = true WHERE id=?")
|
||||||
|
@SQLRestriction("deleted = false")
|
||||||
@NoRangeOverlap(
|
@NoRangeOverlap(
|
||||||
min = "tiradaMin",
|
min = "tiradaMin",
|
||||||
max = "tiradaMax",
|
max = "tiradaMax",
|
||||||
id = "id",
|
id = "id",
|
||||||
partitionBy = {"tipoEncuadernacion","tipoCubierta"},
|
partitionBy = {},
|
||||||
deletedFlag = "deleted", // <- si usas soft delete
|
deletedFlag = "deleted", // <- si usas soft delete
|
||||||
deletedActiveValue = false, // activo cuando deleted == false
|
deletedActiveValue = false, // activo cuando deleted == false
|
||||||
message = "{validation.range.overlaps}",
|
message = "{validation.range.overlaps}",
|
||||||
invalidRangeMessage = "{validation.range.invalid}"
|
invalidRangeMessage = "{validation.range.invalid}"
|
||||||
)
|
)
|
||||||
@Entity
|
|
||||||
@Table(name = "margenes_presupuesto")
|
|
||||||
@SQLDelete(sql = "UPDATE margenes_presupuesto SET deleted = TRUE, deleted_at = NOW() WHERE id = ?")
|
|
||||||
@SQLRestriction("deleted = false")
|
|
||||||
public class MargenPresupuesto {
|
public class MargenPresupuesto {
|
||||||
|
|
||||||
@Id
|
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@Column(name="tipo_encuadernacion", nullable = false, length = 50)
|
@Column(name="importe_min", nullable=false, precision=12, scale=2)
|
||||||
@NotNull(message="{validation.required}")
|
@NotNull(message="{validation.required}")
|
||||||
@Enumerated(EnumType.STRING)
|
private BigDecimal importeMin;
|
||||||
private TipoEncuadernacion tipoEncuadernacion;
|
|
||||||
|
|
||||||
@Column(name="tipo_cubierta", nullable = false, length = 50)
|
@Column(name="importe_max", nullable=false, precision=12, scale=2)
|
||||||
@NotNull(message="{validation.required}")
|
@NotNull(message="{validation.required}")
|
||||||
@Enumerated(EnumType.STRING)
|
private BigDecimal importeMax;
|
||||||
private TipoCubierta tipoCubierta;
|
|
||||||
|
|
||||||
@Column(name="tirada_min", nullable = false)
|
@Column(name="margen_min", nullable=false, precision=6, scale=2)
|
||||||
@NotNull(message="{validation.required}")
|
@NotNull(message="{validation.required}")
|
||||||
@Min(value=1, message="{validation.min}")
|
private BigDecimal margenMin;
|
||||||
private Integer tiradaMin;
|
|
||||||
|
|
||||||
@Column(name="tirada_max", nullable = false)
|
@Column(name="margen_max", nullable=false, precision=6, scale=2)
|
||||||
@NotNull(message="{validation.required}")
|
@NotNull(message="{validation.required}")
|
||||||
@Min(value=1, message="{validation.min}")
|
private BigDecimal margenMax;
|
||||||
private Integer tiradaMax;
|
|
||||||
|
|
||||||
@Column(name="margen_max", nullable = false)
|
@Column(nullable=false)
|
||||||
@NotNull(message="{validation.required}")
|
private boolean deleted = false;
|
||||||
@Min(value = 0, message="{validation.min}")
|
|
||||||
@Max(value = 200, message="{validation.max}")
|
|
||||||
private Integer margenMax;
|
|
||||||
|
|
||||||
@Column(name = "margen_min", nullable = false)
|
@Column(name="created_at", nullable=false)
|
||||||
@NotNull(message="{validation.required}")
|
|
||||||
@Min(value = 0, message="{validation.min}")
|
|
||||||
@Max(value = 200, message="{validation.max}")
|
|
||||||
private Integer margenMin;
|
|
||||||
|
|
||||||
@Column(name="created_at", nullable = false, updatable = false)
|
|
||||||
private LocalDateTime createdAt;
|
private LocalDateTime createdAt;
|
||||||
|
|
||||||
@Column(name="updated_at")
|
@Column(name="updated_at", nullable=false)
|
||||||
private LocalDateTime updatedAt;
|
private LocalDateTime updatedAt;
|
||||||
|
|
||||||
@Column(nullable = false)
|
|
||||||
private boolean deleted = false;
|
|
||||||
|
|
||||||
@Column(name="deleted_at")
|
@Column(name="deleted_at")
|
||||||
private LocalDateTime deletedAt;
|
private LocalDateTime deletedAt;
|
||||||
|
|
||||||
|
@PrePersist
|
||||||
|
void onCreate() {
|
||||||
|
createdAt = LocalDateTime.now();
|
||||||
|
updatedAt = createdAt;
|
||||||
|
}
|
||||||
|
@PreUpdate
|
||||||
|
void onUpdate() {
|
||||||
|
updatedAt = LocalDateTime.now();
|
||||||
|
}
|
||||||
public Long getId() {
|
public Long getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setId(Long id) {
|
public void setId(Long id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
public BigDecimal getImporteMin() {
|
||||||
public TipoEncuadernacion getTipoEncuadernacion() {
|
return importeMin;
|
||||||
return tipoEncuadernacion;
|
|
||||||
}
|
}
|
||||||
|
public void setImporteMin(BigDecimal importeMin) {
|
||||||
public void setTipoEncuadernacion(TipoEncuadernacion tipoEncuadernacion) {
|
this.importeMin = importeMin;
|
||||||
this.tipoEncuadernacion = tipoEncuadernacion;
|
|
||||||
}
|
}
|
||||||
|
public BigDecimal getImporteMax() {
|
||||||
public TipoCubierta getTipoCubierta() {
|
return importeMax;
|
||||||
return tipoCubierta;
|
|
||||||
}
|
}
|
||||||
|
public void setImporteMax(BigDecimal importeMax) {
|
||||||
public void setTipoCubierta(TipoCubierta tipoCubierta) {
|
this.importeMax = importeMax;
|
||||||
this.tipoCubierta = tipoCubierta;
|
|
||||||
}
|
}
|
||||||
|
public BigDecimal getMargenMin() {
|
||||||
public Integer getTiradaMin() {
|
|
||||||
return tiradaMin;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTiradaMin(Integer tiradaMin) {
|
|
||||||
this.tiradaMin = tiradaMin;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getTiradaMax() {
|
|
||||||
return tiradaMax;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTiradaMax(Integer tiradaMax) {
|
|
||||||
this.tiradaMax = tiradaMax;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getMargenMax() {
|
|
||||||
return margenMax;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMargenMax(Integer margenMax) {
|
|
||||||
this.margenMax = margenMax;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getMargenMin() {
|
|
||||||
return margenMin;
|
return margenMin;
|
||||||
}
|
}
|
||||||
|
public void setMargenMin(BigDecimal margenMin) {
|
||||||
public void setMargenMin(Integer margenMin) {
|
|
||||||
this.margenMin = margenMin;
|
this.margenMin = margenMin;
|
||||||
}
|
}
|
||||||
|
public BigDecimal getMargenMax() {
|
||||||
public LocalDateTime getCreatedAt() {
|
return margenMax;
|
||||||
return createdAt;
|
|
||||||
}
|
}
|
||||||
|
public void setMargenMax(BigDecimal margenMax) {
|
||||||
public void setCreatedAt(LocalDateTime createdAt) {
|
this.margenMax = margenMax;
|
||||||
this.createdAt = createdAt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public LocalDateTime getUpdatedAt() {
|
|
||||||
return updatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUpdatedAt(LocalDateTime updatedAt) {
|
|
||||||
this.updatedAt = updatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDeleted() {
|
public boolean isDeleted() {
|
||||||
return deleted;
|
return deleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDeleted(boolean deleted) {
|
public void setDeleted(boolean deleted) {
|
||||||
this.deleted = deleted;
|
this.deleted = deleted;
|
||||||
}
|
}
|
||||||
|
public LocalDateTime getCreatedAt() {
|
||||||
|
return createdAt;
|
||||||
|
}
|
||||||
|
public void setCreatedAt(LocalDateTime createdAt) {
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
}
|
||||||
|
public LocalDateTime getUpdatedAt() {
|
||||||
|
return updatedAt;
|
||||||
|
}
|
||||||
|
public void setUpdatedAt(LocalDateTime updatedAt) {
|
||||||
|
this.updatedAt = updatedAt;
|
||||||
|
}
|
||||||
public LocalDateTime getDeletedAt() {
|
public LocalDateTime getDeletedAt() {
|
||||||
return deletedAt;
|
return deletedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDeletedAt(LocalDateTime deletedAt) {
|
public void setDeletedAt(LocalDateTime deletedAt) {
|
||||||
this.deletedAt = deletedAt;
|
this.deletedAt = deletedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PrePersist
|
|
||||||
void onCreate() {
|
|
||||||
this.createdAt = LocalDateTime.now();
|
|
||||||
this.updatedAt = this.createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
@PreUpdate
|
|
||||||
void onUpdate() {
|
|
||||||
this.updatedAt = LocalDateTime.now();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
package com.imprimelibros.erp.configuracion.margenes_presupuestos;
|
package com.imprimelibros.erp.configuracion.margenes_presupuestos;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Arrays;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import org.springframework.context.MessageSource;
|
import org.springframework.context.MessageSource;
|
||||||
import org.springframework.data.jpa.domain.Specification;
|
import org.springframework.data.jpa.domain.Specification;
|
||||||
@ -23,13 +22,13 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
|
||||||
|
import com.imprimelibros.erp.common.Utils;
|
||||||
import com.imprimelibros.erp.datatables.DataTable;
|
import com.imprimelibros.erp.datatables.DataTable;
|
||||||
import com.imprimelibros.erp.datatables.DataTablesParser;
|
import com.imprimelibros.erp.datatables.DataTablesParser;
|
||||||
import com.imprimelibros.erp.datatables.DataTablesRequest;
|
import com.imprimelibros.erp.datatables.DataTablesRequest;
|
||||||
import com.imprimelibros.erp.datatables.DataTablesResponse;
|
import com.imprimelibros.erp.datatables.DataTablesResponse;
|
||||||
import com.imprimelibros.erp.i18n.TranslationService;
|
import com.imprimelibros.erp.i18n.TranslationService;
|
||||||
import com.imprimelibros.erp.presupuesto.dto.Presupuesto.TipoCubierta;
|
import jakarta.persistence.criteria.Predicate;
|
||||||
import com.imprimelibros.erp.presupuesto.dto.Presupuesto.TipoEncuadernacion;
|
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
@ -83,25 +82,46 @@ public class MargenPresupuestoController {
|
|||||||
|
|
||||||
List<String> searchable = List.of(
|
List<String> searchable = List.of(
|
||||||
"id",
|
"id",
|
||||||
"tiradaMin", "tiradaMax",
|
"importeMin", "importeMax",
|
||||||
"margenMin", "margenMax");
|
"margenMin", "margenMax");
|
||||||
|
|
||||||
List<String> orderable = List.of(
|
List<String> orderable = List.of(
|
||||||
"id",
|
"id",
|
||||||
"tipoEncuadernacion",
|
"importeMin",
|
||||||
"tipoCubierta",
|
"importeMax",
|
||||||
"tiradaMin",
|
|
||||||
"tiradaMax",
|
|
||||||
"margenMin",
|
"margenMin",
|
||||||
"margenMax");
|
"margenMax");
|
||||||
|
|
||||||
Specification<MargenPresupuesto> base = (root, query, cb) -> cb.conjunction();
|
Specification<MargenPresupuesto> base = (root, query, cb) -> cb.conjunction();
|
||||||
|
|
||||||
|
Specification<MargenPresupuesto> filtros = (root, query, cb) -> {
|
||||||
|
List<Predicate> ps = new ArrayList<>();
|
||||||
|
|
||||||
|
Utils.parseNumericFilter(dt, "importe_min", locale)
|
||||||
|
.ifPresent(f -> ps.add(f.apply(root.get("importeMin"), cb)));
|
||||||
|
|
||||||
|
Utils.parseNumericFilter(dt, "importe_max", locale)
|
||||||
|
.ifPresent(f -> ps.add(f.apply(root.get("importeMax"), cb)));
|
||||||
|
|
||||||
|
Utils.parseNumericFilter(dt, "margen_min", locale)
|
||||||
|
.ifPresent(f -> ps.add(f.apply(root.get("margenMin"), cb)));
|
||||||
|
|
||||||
|
Utils.parseNumericFilter(dt, "margen_max", locale)
|
||||||
|
.ifPresent(f -> ps.add(f.apply(root.get("margenMax"), cb)));
|
||||||
|
|
||||||
|
return ps.isEmpty() ? cb.conjunction() : cb.and(ps.toArray(new Predicate[0]));
|
||||||
|
};
|
||||||
|
|
||||||
long total = repo.count();
|
long total = repo.count();
|
||||||
|
|
||||||
return DataTable
|
return DataTable
|
||||||
.of(repo, MargenPresupuesto.class, dt, searchable) // 'searchable' en DataTable.java
|
.of(repo, MargenPresupuesto.class, dt, searchable) // 'searchable' en DataTable.java
|
||||||
// edita columnas "reales":
|
// edita columnas "reales":
|
||||||
.orderable(orderable)
|
.orderable(orderable)
|
||||||
|
.edit("importeMin", (margen) -> Utils.formatCurrency(margen.getImporteMin(), locale))
|
||||||
|
.edit("importeMax", (margen) -> Utils.formatCurrency(margen.getImporteMax(), locale))
|
||||||
|
.edit("margenMin", (margen) -> Utils.formatNumber(margen.getMargenMin(), locale))
|
||||||
|
.edit("margenMax", (margen) -> Utils.formatNumber(margen.getMargenMax(), locale))
|
||||||
.add("actions", (margen) -> {
|
.add("actions", (margen) -> {
|
||||||
return "<div class=\"hstack gap-3 flex-wrap\">\n" +
|
return "<div class=\"hstack gap-3 flex-wrap\">\n" +
|
||||||
" <a href=\"javascript:void(0);\" data-id=\"" + margen.getId()
|
" <a href=\"javascript:void(0);\" data-id=\"" + margen.getId()
|
||||||
@ -110,58 +130,8 @@ public class MargenPresupuestoController {
|
|||||||
+ "\" class=\"link-danger btn-delete-margen fs-15\"><i class=\"ri-delete-bin-5-line\"></i></a>\n"
|
+ "\" class=\"link-danger btn-delete-margen fs-15\"><i class=\"ri-delete-bin-5-line\"></i></a>\n"
|
||||||
+ " </div>";
|
+ " </div>";
|
||||||
})
|
})
|
||||||
.edit("tipoEncuadernacion", (margen) -> {
|
|
||||||
return messageSource.getMessage("presupuesto." + margen.getTipoEncuadernacion().name(), null,
|
|
||||||
locale);
|
|
||||||
})
|
|
||||||
.edit("tipoCubierta", (margen) -> {
|
|
||||||
return messageSource.getMessage("presupuesto." + margen.getTipoCubierta().name(), null, locale);
|
|
||||||
})
|
|
||||||
.where(base)
|
.where(base)
|
||||||
// Filtros custom:
|
// Filtros custom:
|
||||||
.filter((builder, req) -> {
|
|
||||||
String fEncuadernacion = Optional.ofNullable(req.raw.get("f_encuadernacion")).orElse("").trim();
|
|
||||||
if (!fEncuadernacion.isEmpty()) {
|
|
||||||
boolean added = false;
|
|
||||||
// 1) Si llega el nombre del enum (p.ej. "fresado", "cosido", ...)
|
|
||||||
try {
|
|
||||||
var encEnum = TipoEncuadernacion.valueOf(fEncuadernacion);
|
|
||||||
builder.add((root, q, cb) -> cb.equal(root.get("tipoEncuadernacion"), encEnum));
|
|
||||||
added = true;
|
|
||||||
} catch (IllegalArgumentException ignored) {
|
|
||||||
}
|
|
||||||
// 2) Si llega la clave i18n (p.ej. "presupuesto.fresado", ...)
|
|
||||||
if (!added) {
|
|
||||||
Arrays.stream(TipoEncuadernacion.values())
|
|
||||||
.filter(e -> e.getMessageKey().equals(fEncuadernacion))
|
|
||||||
.findFirst()
|
|
||||||
.ifPresent(encEnum -> builder
|
|
||||||
.add((root, q, cb) -> cb.equal(root.get("tipoEncuadernacion"), encEnum)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Cubierta ---
|
|
||||||
String fCubierta = Optional.ofNullable(req.raw.get("f_cubierta")).orElse("").trim();
|
|
||||||
if (!fCubierta.isEmpty()) {
|
|
||||||
boolean added = false;
|
|
||||||
// 1) Si llega el nombre del enum (p.ej. "tapaBlanda", "tapaDura",
|
|
||||||
// "tapaDuraLomoRedondo")
|
|
||||||
try {
|
|
||||||
var cubEnum = TipoCubierta.valueOf(fCubierta);
|
|
||||||
builder.add((root, q, cb) -> cb.equal(root.get("tipoCubierta"), cubEnum));
|
|
||||||
added = true;
|
|
||||||
} catch (IllegalArgumentException ignored) {
|
|
||||||
}
|
|
||||||
// 2) Si llega la clave i18n (p.ej. "presupuesto.tapa-blanda", ...)
|
|
||||||
if (!added) {
|
|
||||||
Arrays.stream(TipoCubierta.values())
|
|
||||||
.filter(e -> e.getMessageKey().equals(fCubierta))
|
|
||||||
.findFirst()
|
|
||||||
.ifPresent(cubEnum -> builder
|
|
||||||
.add((root, q, cb) -> cb.equal(root.get("tipoCubierta"), cubEnum)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.toJson(total);
|
.toJson(total);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,10 +178,8 @@ public class MargenPresupuestoController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MargenPresupuesto data = new MargenPresupuesto();
|
MargenPresupuesto data = new MargenPresupuesto();
|
||||||
data.setTipoEncuadernacion(margenPresupuesto.getTipoEncuadernacion());
|
data.setImporteMin(margenPresupuesto.getImporteMin());
|
||||||
data.setTipoCubierta(margenPresupuesto.getTipoCubierta());
|
data.setImporteMax(margenPresupuesto.getImporteMax());
|
||||||
data.setTiradaMin(margenPresupuesto.getTiradaMin());
|
|
||||||
data.setTiradaMax(margenPresupuesto.getTiradaMax());
|
|
||||||
data.setMargenMax(margenPresupuesto.getMargenMax());
|
data.setMargenMax(margenPresupuesto.getMargenMax());
|
||||||
data.setMargenMin(margenPresupuesto.getMargenMin());
|
data.setMargenMin(margenPresupuesto.getMargenMin());
|
||||||
|
|
||||||
@ -243,7 +211,6 @@ public class MargenPresupuestoController {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@PutMapping("/{id}")
|
@PutMapping("/{id}")
|
||||||
public String edit(
|
public String edit(
|
||||||
@PathVariable Long id,
|
@PathVariable Long id,
|
||||||
@ -268,10 +235,8 @@ public class MargenPresupuestoController {
|
|||||||
var entity = uOpt.get();
|
var entity = uOpt.get();
|
||||||
|
|
||||||
// 3) Copiar solamente campos editables
|
// 3) Copiar solamente campos editables
|
||||||
entity.setTipoEncuadernacion(form.getTipoEncuadernacion());
|
entity.setImporteMin(form.getImporteMin());
|
||||||
entity.setTipoCubierta(form.getTipoCubierta());
|
entity.setImporteMax(form.getImporteMax());
|
||||||
entity.setTiradaMin(form.getTiradaMin());
|
|
||||||
entity.setTiradaMax(form.getTiradaMax());
|
|
||||||
entity.setMargenMax(form.getMargenMax());
|
entity.setMargenMax(form.getMargenMax());
|
||||||
entity.setMargenMin(form.getMargenMin());
|
entity.setMargenMin(form.getMargenMin());
|
||||||
|
|
||||||
@ -329,9 +294,11 @@ public class MargenPresupuestoController {
|
|||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
.body(Map.of("message",
|
.body(Map.of("message",
|
||||||
messageSource.getMessage("margenes-presupuesto.error.delete-internal-error", null, locale)));
|
messageSource.getMessage("margenes-presupuesto.error.delete-internal-error", null,
|
||||||
|
locale)));
|
||||||
}
|
}
|
||||||
}).orElseGet(() -> ResponseEntity.status(HttpStatus.NOT_FOUND)
|
}).orElseGet(() -> ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||||
.body(Map.of("message", messageSource.getMessage("margenes-presupuesto.error.not-found", null, locale))));
|
.body(Map.of("message",
|
||||||
|
messageSource.getMessage("margenes-presupuesto.error.not-found", null, locale))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,40 +1,36 @@
|
|||||||
package com.imprimelibros.erp.configuracion.margenes_presupuestos;
|
package com.imprimelibros.erp.configuracion.margenes_presupuestos;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
import org.springframework.data.jpa.repository.Query;
|
import org.springframework.data.jpa.repository.Query;
|
||||||
import org.springframework.data.repository.query.Param;
|
import org.springframework.data.repository.query.Param;
|
||||||
|
|
||||||
import com.imprimelibros.erp.presupuesto.dto.Presupuesto.TipoCubierta;
|
|
||||||
import com.imprimelibros.erp.presupuesto.dto.Presupuesto.TipoEncuadernacion;
|
|
||||||
|
|
||||||
public interface MargenPresupuestoDao
|
public interface MargenPresupuestoDao
|
||||||
extends JpaRepository<MargenPresupuesto, Long>, JpaSpecificationExecutor<MargenPresupuesto> {
|
extends JpaRepository<MargenPresupuesto, Long>, JpaSpecificationExecutor<MargenPresupuesto> {
|
||||||
|
|
||||||
@Query("""
|
@Query("""
|
||||||
SELECT COUNT(m) FROM MargenPresupuesto m
|
SELECT COUNT(m) FROM MargenPresupuesto m
|
||||||
WHERE m.deleted = false
|
WHERE m.deleted = false
|
||||||
AND m.tipoEncuadernacion = :enc
|
AND ( ( :min BETWEEN m.importeMin AND m.importeMax )
|
||||||
AND m.tipoCubierta = :cub
|
OR ( :max BETWEEN m.importeMin AND m.importeMax )
|
||||||
AND (:id IS NULL OR m.id <> :id)
|
OR ( m.importeMin BETWEEN :min AND :max )
|
||||||
AND NOT (m.tiradaMax < :min OR m.tiradaMin > :max)
|
OR ( m.importeMax BETWEEN :min AND :max ) )
|
||||||
""")
|
AND ( :excludeId IS NULL OR m.id <> :excludeId )
|
||||||
|
""")
|
||||||
long countOverlaps(
|
long countOverlaps(
|
||||||
@Param("enc") TipoEncuadernacion enc,
|
@Param("min") BigDecimal min,
|
||||||
@Param("cub") TipoCubierta cub,
|
@Param("max") BigDecimal max,
|
||||||
@Param("min") Integer min,
|
@Param("excludeId") Long excludeId);
|
||||||
@Param("max") Integer max,
|
|
||||||
@Param("id") Long id);
|
|
||||||
|
|
||||||
@Query("""
|
@Query("""
|
||||||
SELECT m FROM MargenPresupuesto m
|
SELECT m FROM MargenPresupuesto m
|
||||||
WHERE m.deleted = false
|
WHERE m.deleted = false
|
||||||
AND m.tipoEncuadernacion = :enc
|
AND :importe BETWEEN m.importeMin AND m.importeMax
|
||||||
AND m.tipoCubierta = :cub
|
""")
|
||||||
AND :tirada BETWEEN m.tiradaMin AND m.tiradaMax
|
Optional<MargenPresupuesto> findByImporte(@Param("importe") BigDecimal importe);
|
||||||
""")
|
|
||||||
MargenPresupuesto findByTipoAndTirada(
|
|
||||||
@Param("enc") TipoEncuadernacion enc,
|
|
||||||
@Param("cub") TipoCubierta cub,
|
|
||||||
@Param("tirada") Integer tirada);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,12 @@
|
|||||||
package com.imprimelibros.erp.configuracion.margenes_presupuestos;
|
package com.imprimelibros.erp.configuracion.margenes_presupuestos;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import com.imprimelibros.erp.presupuesto.dto.Presupuesto.TipoCubierta;
|
|
||||||
import com.imprimelibros.erp.presupuesto.dto.Presupuesto.TipoEncuadernacion;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Transactional
|
@Transactional
|
||||||
public class MargenPresupuestoService {
|
public class MargenPresupuestoService {
|
||||||
@ -27,17 +25,19 @@ public class MargenPresupuestoService {
|
|||||||
return dao.findById(id);
|
return dao.findById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MargenPresupuesto save(MargenPresupuesto entity) {
|
public Optional<MargenPresupuesto> findByImporte(BigDecimal importe){
|
||||||
return dao.save(entity);
|
return dao.findByImporte(importe);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MargenPresupuesto save(MargenPresupuesto e) {
|
||||||
|
return dao.save(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void delete(Long id) {
|
public void delete(Long id) {
|
||||||
dao.deleteById(id);
|
dao.deleteById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasOverlap(BigDecimal min, BigDecimal max, Long excludeId) {
|
||||||
public boolean hasOverlap(TipoEncuadernacion enc, TipoCubierta cub, Integer min, Integer max, Long excludeId) {
|
return dao.countOverlaps(min, max, excludeId) > 0;
|
||||||
long count = dao.countOverlaps(enc, cub, min, max, excludeId);
|
|
||||||
return count > 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,15 +9,34 @@ public class DataTablesRequest {
|
|||||||
public Search search = new Search();
|
public Search search = new Search();
|
||||||
public List<Order> order = new ArrayList<>();
|
public List<Order> order = new ArrayList<>();
|
||||||
public List<Column> columns = new ArrayList<>();
|
public List<Column> columns = new ArrayList<>();
|
||||||
public Map<String,String> raw = new HashMap<>(); // <- params extra
|
public Map<String, String> raw = new HashMap<>(); // <- params extra
|
||||||
|
|
||||||
|
public static class Search {
|
||||||
|
public String value = "";
|
||||||
|
public boolean regex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Order {
|
||||||
|
public int column;
|
||||||
|
public String dir;
|
||||||
|
}
|
||||||
|
|
||||||
public static class Search { public String value=""; public boolean regex; }
|
|
||||||
public static class Order { public int column; public String dir; }
|
|
||||||
public static class Column {
|
public static class Column {
|
||||||
public String data;
|
public String data;
|
||||||
public String name;
|
public String name;
|
||||||
public boolean searchable=true;
|
public boolean searchable = true;
|
||||||
public boolean orderable=true;
|
public boolean orderable = true;
|
||||||
public Search search=new Search();
|
public Search search = new Search();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getColumnSearch(String columnName) {
|
||||||
|
if (columnName == null || columns == null)
|
||||||
|
return null;
|
||||||
|
for (Column col : columns) {
|
||||||
|
if (col != null && col.name != null && col.name.equalsIgnoreCase(columnName)) {
|
||||||
|
return col.search != null ? col.search.value : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -18,6 +18,8 @@ import com.imprimelibros.erp.presupuesto.dto.Presupuesto.TipoCubierta;
|
|||||||
import com.imprimelibros.erp.presupuesto.dto.Presupuesto.TipoEncuadernacion;
|
import com.imprimelibros.erp.presupuesto.dto.Presupuesto.TipoEncuadernacion;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
@ -34,7 +36,8 @@ public class skApiClient {
|
|||||||
private final MargenPresupuestoDao margenPresupuestoDao;
|
private final MargenPresupuestoDao margenPresupuestoDao;
|
||||||
private final MessageSource messageSource;
|
private final MessageSource messageSource;
|
||||||
|
|
||||||
public skApiClient(AuthService authService, MargenPresupuestoDao margenPresupuestoDao, MessageSource messageSource) {
|
public skApiClient(AuthService authService, MargenPresupuestoDao margenPresupuestoDao,
|
||||||
|
MessageSource messageSource) {
|
||||||
this.authService = authService;
|
this.authService = authService;
|
||||||
this.restTemplate = new RestTemplate();
|
this.restTemplate = new RestTemplate();
|
||||||
this.margenPresupuestoDao = margenPresupuestoDao;
|
this.margenPresupuestoDao = margenPresupuestoDao;
|
||||||
@ -80,23 +83,28 @@ public class skApiClient {
|
|||||||
data.get("precios"), new TypeReference<List<Double>>() {
|
data.get("precios"), new TypeReference<List<Double>>() {
|
||||||
});
|
});
|
||||||
|
|
||||||
for (int i = 0; i < tiradas.size(); i++) {
|
for (int i = 0; i < precios.size(); i++) {
|
||||||
int tirada = tiradas.get(i);
|
BigDecimal importe = new BigDecimal(precios.get(i));
|
||||||
|
|
||||||
MargenPresupuesto margen = margenPresupuestoDao.findByTipoAndTirada(
|
BigDecimal importeTotal = importe.multiply(BigDecimal.valueOf(tiradas.get(i)));
|
||||||
tipoEncuadernacion, tipoCubierta, tirada);
|
|
||||||
|
MargenPresupuesto margen = margenPresupuestoDao
|
||||||
|
.findByImporte(importeTotal).orElse(null);
|
||||||
|
|
||||||
if (margen != null) {
|
if (margen != null) {
|
||||||
double margenValue = calcularMargen(
|
BigDecimal margenValue = calcularMargen(
|
||||||
tirada,
|
importeTotal,
|
||||||
margen.getTiradaMin(),
|
margen.getImporteMin(),
|
||||||
margen.getTiradaMax(),
|
margen.getImporteMax(),
|
||||||
margen.getMargenMax(),
|
margen.getMargenMax(),
|
||||||
margen.getMargenMin());
|
margen.getMargenMin());
|
||||||
double nuevoPrecio = precios.get(i) * (1 + margenValue / 100.0);
|
BigDecimal nuevoPrecio = new BigDecimal(precios.get(i)).multiply(BigDecimal.ONE
|
||||||
precios.set(i, Math.round(nuevoPrecio * 10000.0) / 10000.0); // redondear a 2 decimales
|
.add(margenValue.divide(BigDecimal.valueOf(100), RoundingMode.HALF_UP)));
|
||||||
|
precios.set(i, nuevoPrecio.setScale(4, RoundingMode.HALF_UP).doubleValue()); // redondear
|
||||||
|
// a 4
|
||||||
|
// decimales
|
||||||
} else {
|
} else {
|
||||||
System.out.println("No se encontró margen para tirada " + tirada);
|
System.out.println("No se encontró margen para importe " + importe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +162,8 @@ public class skApiClient {
|
|||||||
JsonNode root = mapper.readTree(jsonResponse);
|
JsonNode root = mapper.readTree(jsonResponse);
|
||||||
|
|
||||||
if (root.get("data") == null || !root.get("data").isInt()) {
|
if (root.get("data") == null || !root.get("data").isInt()) {
|
||||||
throw new RuntimeException(messageSource.getMessage("presupuesto.errores.error-interior", new Object[]{1} , locale));
|
throw new RuntimeException(
|
||||||
|
messageSource.getMessage("presupuesto.errores.error-interior", new Object[] { 1 }, locale));
|
||||||
}
|
}
|
||||||
|
|
||||||
return root.get("data").asInt();
|
return root.get("data").asInt();
|
||||||
@ -227,13 +236,15 @@ public class skApiClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static double calcularMargen(
|
private static BigDecimal calcularMargen(
|
||||||
int tirada, int tiradaMin, int tiradaMax,
|
BigDecimal importe, BigDecimal importeMin, BigDecimal importeMax,
|
||||||
double margenMax, double margenMin) {
|
BigDecimal margenMax, BigDecimal margenMin) {
|
||||||
if (tirada <= tiradaMin)
|
if (importe.compareTo(importeMin) <= 0)
|
||||||
return margenMax;
|
return margenMax;
|
||||||
if (tirada >= tiradaMax)
|
if (importe.compareTo(importeMax) >= 0)
|
||||||
return margenMin;
|
return margenMin;
|
||||||
return margenMax - ((double) (tirada - tiradaMin) / (tiradaMax - tiradaMin)) * (margenMax - margenMin);
|
return margenMax.subtract(margenMax.subtract(margenMin)
|
||||||
|
.multiply(importe.subtract(importeMin)
|
||||||
|
.divide(importeMax.subtract(importeMin), RoundingMode.HALF_UP)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -26,7 +26,7 @@ public class TamanioValidator implements ConstraintValidator<Tamanio, Presupuest
|
|||||||
Integer max = variableService.getValorEntero("ancho_alto_max");
|
Integer max = variableService.getValorEntero("ancho_alto_max");
|
||||||
|
|
||||||
|
|
||||||
if (presupuesto.getAncho() <= min || presupuesto.getAncho() >= max) {
|
if (presupuesto.getAncho() < min || presupuesto.getAncho() > max) {
|
||||||
|
|
||||||
String mensajeInterpolado = messageSource.getMessage(
|
String mensajeInterpolado = messageSource.getMessage(
|
||||||
"presupuesto.errores.ancho.min_max", // clave del mensaje
|
"presupuesto.errores.ancho.min_max", // clave del mensaje
|
||||||
|
|||||||
@ -6,18 +6,14 @@ margenes-presupuesto.editar=Editar margen
|
|||||||
margenes-presupuesto.eliminar=Eliminar
|
margenes-presupuesto.eliminar=Eliminar
|
||||||
|
|
||||||
margenes-presupuesto.tabla.id=ID
|
margenes-presupuesto.tabla.id=ID
|
||||||
margenes-presupuesto.tabla.tipo_encuadernacion=Tipo encuadernación
|
margenes-presupuesto.tabla.importe_minimo=Importe Mín.
|
||||||
margenes-presupuesto.tabla.tipo_cubierta=Tipo cubierta
|
margenes-presupuesto.tabla.importe_maximo=Importe Máx.
|
||||||
margenes-presupuesto.tabla.tirada_minima=Tirada Mín.
|
|
||||||
margenes-presupuesto.tabla.tirada_maxima=Tirada Máx.
|
|
||||||
margenes-presupuesto.tabla.margen_minimo=Margen Mín.
|
margenes-presupuesto.tabla.margen_minimo=Margen Mín.
|
||||||
margenes-presupuesto.tabla.margen_maximo=Margen Máx.
|
margenes-presupuesto.tabla.margen_maximo=Margen Máx.
|
||||||
margenes-presupuesto.tabla.acciones=Acciones
|
margenes-presupuesto.tabla.acciones=Acciones
|
||||||
|
|
||||||
margenes-presupuesto.form.tipo_encuadernacion=Tipo de encuadernación
|
margenes-presupuesto.form.importe_minimo=Importe mínimo
|
||||||
margenes-presupuesto.form.tipo_cubierta=Tipo de cubierta
|
margenes-presupuesto.form.importe_maximo=Importe máximo
|
||||||
margenes-presupuesto.form.tirada_minima=Tirada mínima
|
|
||||||
margenes-presupuesto.form.tirada_maxima=Tirada máxima
|
|
||||||
margenes-presupuesto.form.margen_minimo=Margen mínimo (%)
|
margenes-presupuesto.form.margen_minimo=Margen mínimo (%)
|
||||||
margenes-presupuesto.form.margen_maximo=Margen máximo (%)
|
margenes-presupuesto.form.margen_maximo=Margen máximo (%)
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import {normalizeNumericFilter} from '../../utils.js';
|
||||||
|
|
||||||
(() => {
|
(() => {
|
||||||
// si jQuery está cargado, añade CSRF a AJAX
|
// si jQuery está cargado, añade CSRF a AJAX
|
||||||
const csrfToken = document.querySelector('meta[name="_csrf"]')?.getAttribute('content');
|
const csrfToken = document.querySelector('meta[name="_csrf"]')?.getAttribute('content');
|
||||||
@ -22,7 +24,6 @@
|
|||||||
processing: true,
|
processing: true,
|
||||||
serverSide: true,
|
serverSide: true,
|
||||||
orderCellsTop: true,
|
orderCellsTop: true,
|
||||||
stateSave: true,
|
|
||||||
pageLength: 50,
|
pageLength: 50,
|
||||||
language: { url: '/assets/libs/datatables/i18n/' + language + '.json' },
|
language: { url: '/assets/libs/datatables/i18n/' + language + '.json' },
|
||||||
responsive: true,
|
responsive: true,
|
||||||
@ -45,18 +46,12 @@
|
|||||||
ajax: {
|
ajax: {
|
||||||
url: '/configuracion/margenes-presupuesto/datatable',
|
url: '/configuracion/margenes-presupuesto/datatable',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
data: function (d) {
|
|
||||||
d.f_encuadernacion = $('#search-encuadernacion').val() || ''; // 'USER' | 'ADMIN' | 'SUPERADMIN' | ''
|
|
||||||
d.f_cubierta = $('#search-cubierta').val() || ''; // 'true' | 'false' | ''
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
order: [[0, 'asc']],
|
order: [[0, 'asc']],
|
||||||
columns: [
|
columns: [
|
||||||
{ data: 'id', name: 'id', orderable: true },
|
{ data: 'id', name: 'id', orderable: true },
|
||||||
{ data: 'tipoEncuadernacion', name: 'tipoEncuadernacion', orderable: true },
|
{ data: 'importeMin', name: 'importeMin', orderable: true },
|
||||||
{ data: 'tipoCubierta', name: 'tipoCubierta', orderable: true },
|
{ data: 'importeMax', name: 'importeMax', orderable: true },
|
||||||
{ data: 'tiradaMin', name: 'tiradaMin', orderable: true },
|
|
||||||
{ data: 'tiradaMax', name: 'tiradaMax', orderable: true },
|
|
||||||
{ data: 'margenMax', name: 'margenMax', orderable: true },
|
{ data: 'margenMax', name: 'margenMax', orderable: true },
|
||||||
{ data: 'margenMin', name: 'margenMin', orderable: true },
|
{ data: 'margenMin', name: 'margenMin', orderable: true },
|
||||||
{ data: 'actions', name: 'actions' }
|
{ data: 'actions', name: 'actions' }
|
||||||
@ -69,7 +64,7 @@
|
|||||||
const colIndex = table.settings()[0].aoColumns.findIndex(c => c.name === colName);
|
const colIndex = table.settings()[0].aoColumns.findIndex(c => c.name === colName);
|
||||||
|
|
||||||
if (colIndex >= 0) {
|
if (colIndex >= 0) {
|
||||||
table.column(colIndex).search(this.value).draw();
|
table.column(colIndex).search(normalizeNumericFilter(this.value)).draw();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -65,3 +65,16 @@ export function bracketPrefix(obj, prefix) {
|
|||||||
});
|
});
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function normalizeNumericFilter(input) {
|
||||||
|
if (!input) return input;
|
||||||
|
// Convierte todos los números del string:
|
||||||
|
// - Quita separadores de miles con punto
|
||||||
|
// - Cambia coma decimal por punto
|
||||||
|
// Mantiene operadores (>=, <=, <, >) y rangos con '-'
|
||||||
|
return input.replace(
|
||||||
|
/\d{1,3}(?:\.\d{3})*(?:,\d+)?|\d+(?:,\d+)?/g,
|
||||||
|
(num) => num.replace(/\./g, '').replace(',', '.')
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -9,41 +9,17 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label th:text="#{margenes-presupuesto.form.tipo_encuadernacion}" for="tipo_encuadernacion">Tipo de Encuadernación</label>
|
<label th:text="#{margenes-presupuesto.form.importe_minimo}" for="importe_minimo">Importe Mínimo</label>
|
||||||
<select class="form-control" id="tipo_encuadernacion" th:field="*{tipoEncuadernacion}" required
|
<input type="number" class="form-control" id="importe_minimo" th:field="*{importeMin}" min="1"
|
||||||
th:classappend="${#fields.hasErrors('tipoEncuadernacion')} ? ' is-invalid'">
|
th:classappend="${#fields.hasErrors('importeMin')} ? ' is-invalid'" required>
|
||||||
<option value="fresado" th:text="#{presupuesto.fresado}" selected>Fresado</option>
|
<div class="invalid-feedback" th:if="${#fields.hasErrors('importeMin')}" th:errors="*{importeMin}">Error</div>
|
||||||
<option value="cosido" th:text="#{presupuesto.cosido}">Cosido</option>
|
|
||||||
<option value="espiral" th:text="#{presupuesto.espiral}">Espiral</option>
|
|
||||||
<option value="wireo" th:text="#{presupuesto.wireo}">Wire-O</option>
|
|
||||||
<option value="grapado" th:text="#{presupuesto.grapado}">Grapado</option>
|
|
||||||
</select>
|
|
||||||
<div class="invalid-feedback" th:if="${#fields.hasErrors('tipoEncuadernacion')}" th:errors="*{tipoEncuadernacion}">Error</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label th:text="#{margenes-presupuesto.form.tipo_cubierta}" for="tipo_cubierta">Tipo de Cubierta</label>
|
<label th:text="#{margenes-presupuesto.form.importe_maximo}" for="importe_maximo">Importe Máximo</label>
|
||||||
<select class="form-control" id="tipo_cubierta" th:field="*{tipoCubierta}" required
|
<input type="number" class="form-control" id="importe_maximo" th:field="*{importeMax}" min="1"
|
||||||
th:classappend="${#fields.hasErrors('tipoCubierta')} ? ' is-invalid'">
|
th:classappend="${#fields.hasErrors('importeMax')} ? ' is-invalid'" required>
|
||||||
<option value="tapaBlanda" th:text="#{presupuesto.tapaBlanda}" selected>Tapa Blanda</option>
|
<div class="invalid-feedback" th:if="${#fields.hasErrors('importeMax')}" th:errors="*{importeMax}">Error</div>
|
||||||
<option value="tapaDura" th:text="#{presupuesto.tapaDura}">Tapa Dura</option>
|
|
||||||
<option value="tapaDuraLomoRedondo" th:text="#{presupuesto.tapaDuraLomoRedondo}">Tapa Dura Lomo Redondo</option>
|
|
||||||
</select>
|
|
||||||
<div class="invalid-feedback" th:if="${#fields.hasErrors('tipoCubierta')}" th:errors="*{tipoCubierta}">Error</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label th:text="#{margenes-presupuesto.form.tirada_minima}" for="tirada_minima">Tirada Mínima</label>
|
|
||||||
<input type="number" class="form-control" id="tirada_minima" th:field="*{tiradaMin}" min="1"
|
|
||||||
th:classappend="${#fields.hasErrors('tiradaMin')} ? ' is-invalid'" required>
|
|
||||||
<div class="invalid-feedback" th:if="${#fields.hasErrors('tiradaMin')}" th:errors="*{tiradaMin}">Error</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label th:text="#{margenes-presupuesto.form.tirada_maxima}" for="tirada_maxima">Tirada Máxima</label>
|
|
||||||
<input type="number" class="form-control" id="tirada_maxima" th:field="*{tiradaMax}" min="1"
|
|
||||||
th:classappend="${#fields.hasErrors('tiradaMax')} ? ' is-invalid'" required>
|
|
||||||
<div class="invalid-feedback" th:if="${#fields.hasErrors('tiradaMax')}" th:errors="*{tiradaMax}">Error</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|||||||
@ -45,11 +45,8 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col" th:text="#{margenes-presupuesto.tabla.id}">ID</th>
|
<th scope="col" th:text="#{margenes-presupuesto.tabla.id}">ID</th>
|
||||||
<th scope="col" th:text="#{margenes-presupuesto.tabla.tipo_encuadernacion}">Tipo
|
<th scope="col" th:text="#{margenes-presupuesto.tabla.importe_minimo}">Importe Mín.</th>
|
||||||
encuadernación</th>
|
<th scope="col" th:text="#{margenes-presupuesto.tabla.importe_maximo}">Importe Máx.</th>
|
||||||
<th scope="col" th:text="#{margenes-presupuesto.tabla.tipo_cubierta}">Tipo cubierta</th>
|
|
||||||
<th scope="col" th:text="#{margenes-presupuesto.tabla.tirada_minima}">Tirada Mín.</th>
|
|
||||||
<th scope="col" th:text="#{margenes-presupuesto.tabla.tirada_maxima}">Tirada Máx.</th>
|
|
||||||
<th scope="col" th:text="#{margenes-presupuesto.tabla.margen_maximo}">Margen Máx.</th>
|
<th scope="col" th:text="#{margenes-presupuesto.tabla.margen_maximo}">Margen Máx.</th>
|
||||||
<th scope="col" th:text="#{margenes-presupuesto.tabla.margen_minimo}">Margen Mín.</th>
|
<th scope="col" th:text="#{margenes-presupuesto.tabla.margen_minimo}">Margen Mín.</th>
|
||||||
<th scope="col" th:text="#{margenes-presupuesto.tabla.acciones}">Acciones</th>
|
<th scope="col" th:text="#{margenes-presupuesto.tabla.acciones}">Acciones</th>
|
||||||
@ -58,33 +55,12 @@
|
|||||||
<th><input type="text" class="form-control form-control-sm margenes-presupuesto-filter"
|
<th><input type="text" class="form-control form-control-sm margenes-presupuesto-filter"
|
||||||
data-col="id" /></th>
|
data-col="id" /></th>
|
||||||
<th>
|
<th>
|
||||||
<select class="form-select form-select-sm margenes-presupuesto-select-filter"
|
<input type="text" class="form-control form-control-sm margenes-presupuesto-filter"
|
||||||
id="search-encuadernacion">
|
data-col="importeMin" />
|
||||||
<option value="" th:text="#{margenes-presupuesto.todos}">Todos</option>
|
|
||||||
<option value="fresado" th:text="#{presupuesto.fresado}">Fresado</option>
|
|
||||||
<option value="cosido" th:text="#{presupuesto.cosido}">Cosido</option>
|
|
||||||
<option value="espiral" th:text="#{presupuesto.espiral}">Espiral</option>
|
|
||||||
<option value="wireo" th:text="#{presupuesto.wireo}">Wireo</option>
|
|
||||||
<option value="grapado" th:text="#{presupuesto.grapado}">Grapado</option>
|
|
||||||
</select>
|
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
<select class="form-select form-select-sm margenes-presupuesto-select-filter"
|
|
||||||
id="search-cubierta">
|
|
||||||
<option value="" th:text="#{margenes-presupuesto.todos}">Todos</option>
|
|
||||||
<option value="tapaBlanda" th:text="#{presupuesto.tapa-blanda}"></option>
|
|
||||||
<option value="tapaDura" th:text="#{presupuesto.tapa-dura}"></option>
|
|
||||||
<option value="tapaDuraLomoRedondo" th:text="#{presupuesto.tapa-dura-lomo-redondo}">
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
<input type="text" class="form-control form-control-sm margenes-presupuesto-filter"
|
<input type="text" class="form-control form-control-sm margenes-presupuesto-filter"
|
||||||
data-col="tiradaMin" />
|
data-col="importeMax" />
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
<input type="text" class="form-control form-control-sm margenes-presupuesto-filter"
|
|
||||||
data-col="tiradaMax" />
|
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
<input type="text" class="form-control form-control-sm margenes-presupuesto-filter"
|
<input type="text" class="form-control form-control-sm margenes-presupuesto-filter"
|
||||||
@ -122,7 +98,7 @@
|
|||||||
<script th:src="@{/assets/libs/datatables/buttons.print.min.js}"></script>
|
<script th:src="@{/assets/libs/datatables/buttons.print.min.js}"></script>
|
||||||
<script th:src="@{/assets/libs/datatables/buttons.colVis.min.js}"></script>
|
<script th:src="@{/assets/libs/datatables/buttons.colVis.min.js}"></script>
|
||||||
|
|
||||||
<script th:src="@{/assets/js/pages/imprimelibros/configuracion/margenes-presupuesto/list.js}"></script>
|
<script type="module" th:src="@{/assets/js/pages/imprimelibros/configuracion/margenes-presupuesto/list.js}"></script>
|
||||||
|
|
||||||
</th:block>
|
</th:block>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
Reference in New Issue
Block a user