quitado tipo de entrega de todos sitios. Trabajando en el iva dependiendo de la dirección de facturación

This commit is contained in:
2026-02-13 21:19:25 +01:00
parent cef0af1bd2
commit fffc2b91c1
13 changed files with 128 additions and 83 deletions

View File

@ -80,7 +80,7 @@ public class CartController {
else if (direcciones != null && direcciones.containsKey("direcciones")) else if (direcciones != null && direcciones.containsKey("direcciones"))
model.addAttribute("direcciones", direcciones.get("direcciones")); model.addAttribute("direcciones", direcciones.get("direcciones"));
var summary = service.getCartSummary(cart, locale); var summary = service.getCartSummary(cart, locale, true);
model.addAttribute("cartSummary", summary); model.addAttribute("cartSummary", summary);
if (summary.get("errorShipmentCost") != null && (Boolean) summary.get("errorShipmentCost")) if (summary.get("errorShipmentCost") != null && (Boolean) summary.get("errorShipmentCost"))
model.addAttribute("errorEnvio", true); model.addAttribute("errorEnvio", true);
@ -165,7 +165,7 @@ public class CartController {
try { try {
service.updateCart(id, updateRequest); service.updateCart(id, updateRequest);
var cartSummary = service.getCartSummary(service.getCartById(id), locale); var cartSummary = service.getCartSummary(service.getCartById(id), locale, true);
model.addAttribute("cartSummary", cartSummary); model.addAttribute("cartSummary", cartSummary);
return "imprimelibros/cart/_cartSummary :: cartSummary(summary=${cartSummary})"; return "imprimelibros/cart/_cartSummary :: cartSummary(summary=${cartSummary})";

View File

@ -163,7 +163,7 @@ public class CartService {
return itemRepo.findByCartId(cart.getId()).size(); return itemRepo.findByCartId(cart.getId()).size();
} }
public Map<String, Object> getCartSummaryRaw(Cart cart, Locale locale) { public Map<String, Object> getCartSummaryRaw(Cart cart, Locale locale, Boolean hasTaxes) {
double base = 0.0; double base = 0.0;
double iva4 = 0.0; double iva4 = 0.0;
@ -269,6 +269,11 @@ public class CartService {
} }
} }
if(!hasTaxes) {
iva4 = 0.0;
iva21 = 0.0;
}
double totalBeforeDiscount = base + iva4 + iva21 + shipment; double totalBeforeDiscount = base + iva4 + iva21 + shipment;
int fidelizacion = this.getDescuentoFidelizacion(cart.getUserId()); int fidelizacion = this.getDescuentoFidelizacion(cart.getUserId());
double descuento = totalBeforeDiscount * fidelizacion / 100.0; double descuento = totalBeforeDiscount * fidelizacion / 100.0;
@ -318,8 +323,8 @@ public class CartService {
return 0; return 0;
} }
public Map<String, Object> getCartSummary(Cart cart, Locale locale) { public Map<String, Object> getCartSummary(Cart cart, Locale locale, Boolean hasTaxes) {
Map<String, Object> raw = getCartSummaryRaw(cart, locale); Map<String, Object> raw = getCartSummaryRaw(cart, locale, hasTaxes);
double base = (Double) raw.get("base"); double base = (Double) raw.get("base");
double iva4 = (Double) raw.get("iva4"); double iva4 = (Double) raw.get("iva4");

View File

@ -22,6 +22,7 @@ import com.imprimelibros.erp.direcciones.DireccionService;
import com.imprimelibros.erp.cart.Cart; import com.imprimelibros.erp.cart.Cart;
import com.imprimelibros.erp.cart.CartService; import com.imprimelibros.erp.cart.CartService;
@Controller @Controller
@RequestMapping("/checkout") @RequestMapping("/checkout")
public class CheckoutController { public class CheckoutController {
@ -58,10 +59,25 @@ public class CheckoutController {
Long userId = Utils.currentUserId(principal); Long userId = Utils.currentUserId(principal);
Cart cart = cartService.getOrCreateActiveCart(userId); Cart cart = cartService.getOrCreateActiveCart(userId);
model.addAttribute("summary", cartService.getCartSummary(cart, locale)); model.addAttribute("summary", cartService.getCartSummary(cart, locale, true));
return "imprimelibros/checkout/checkout"; // crea esta vista si quieres (tabla simple) return "imprimelibros/checkout/checkout"; // crea esta vista si quieres (tabla simple)
} }
@GetMapping({"/get-summary", "/get-summary/{direccionId}"})
public String getCheckoutSummary(@PathVariable(required = false) Long direccionId, Principal principal, Model model, Locale locale) {
Long userId = Utils.currentUserId(principal);
Cart cart = cartService.getOrCreateActiveCart(userId);
Boolean hasTaxes = true;
if(direccionId != null) {
hasTaxes = direccionService.hasTaxes(direccionId);
}
Map<String, Object> summary = cartService.getCartSummary(cart, locale, hasTaxes);
model.addAttribute("summary", summary);
return "imprimelibros/checkout/_summary :: checkoutSummary(summary=${summary})";
}
@GetMapping("/get-address/{id}") @GetMapping("/get-address/{id}")
public String getDireccionCard(@PathVariable Long id, Model model, Locale locale) { public String getDireccionCard(@PathVariable Long id, Model model, Locale locale) {
Direccion dir = direccionService.findById(id) Direccion dir = direccionService.findById(id)

View File

@ -153,4 +153,26 @@ public class DireccionService {
return false; return false;
} }
public Boolean hasTaxes(Long direccionId) {
if(direccionId == null) {
return true; // Si no hay dirección, asumimos que sí tiene impuestos
}
Optional<Direccion> dir = repo.findById(direccionId);
if (dir == null || dir.isEmpty()) {
throw new RuntimeException("Dirección no encontrada");
}
if(dir.get().getPaisCode3().toLowerCase().equals("esp")) {
int provincia = dir.get().getCp() / 1000;
if (provincia == 35 || provincia == 38 ) {
return false; // Canarias (sin IVA)lñ.
}
return true; // España (todas las provincias)
}
else{
// Fuera de España, asumimos que no tiene impuestos (puedes ajustar esto según tus necesidades)
return false;
}
}
} }

View File

@ -81,7 +81,8 @@ public class PedidoService {
Pedido pedido = new Pedido(); Pedido pedido = new Pedido();
Cart cart = cartService.getCartById(cartId); Cart cart = cartService.getCartById(cartId);
Map<String, Object> cartSummaryRaw = cartService.getCartSummaryRaw(cart, Locale.getDefault()); Boolean hasTaxes = direccionService.hasTaxes(direccionFacturacionId);
Map<String, Object> cartSummaryRaw = cartService.getCartSummaryRaw(cart, Locale.getDefault(), hasTaxes);
// Datos económicos (ojo con las claves, son las del summaryRaw) // Datos económicos (ojo con las claves, son las del summaryRaw)
pedido.setBase((Double) cartSummaryRaw.getOrDefault("base", 0.0d)); pedido.setBase((Double) cartSummaryRaw.getOrDefault("base", 0.0d));

View File

@ -109,21 +109,6 @@ public class Presupuesto extends AbstractAuditedEntity implements Cloneable {
} }
} }
public enum Entrega {
peninsula("presupuesto.entrega.peninsula"),
canarias("presupuesto.entrega.canarias"),
paises_ue("presupuesto.entrega.paises-ue");
private final String messageKey;
Entrega(String messageKey) {
this.messageKey = messageKey;
}
public String getMessageKey() {
return messageKey;
}
}
@Override @Override
public Presupuesto clone() { public Presupuesto clone() {
@ -188,10 +173,6 @@ public class Presupuesto extends AbstractAuditedEntity implements Cloneable {
@Column(name = "iva_reducido") @Column(name = "iva_reducido")
private Boolean ivaReducido; private Boolean ivaReducido;
@Column(name = "entrega_tipo")
@Enumerated(EnumType.STRING)
private Entrega entregaTipo;
@Column(name = "iva_importe_4", precision = 12, scale = 2) @Column(name = "iva_importe_4", precision = 12, scale = 2)
private BigDecimal ivaImporte4; private BigDecimal ivaImporte4;
@ -531,14 +512,6 @@ public class Presupuesto extends AbstractAuditedEntity implements Cloneable {
this.ivaReducido = ivaReducido; this.ivaReducido = ivaReducido;
} }
public Entrega getEntregaTipo() {
return entregaTipo;
}
public void setEntregaTipo(Entrega entregaTipo) {
this.entregaTipo = entregaTipo;
}
public BigDecimal getIvaImporte4() { public BigDecimal getIvaImporte4() {
return ivaImporte4; return ivaImporte4;
} }

View File

@ -37,7 +37,6 @@ public class PresupuestoFormDataMapper {
public String paginasColor = ""; public String paginasColor = "";
public String posicionPaginasColor = ""; public String posicionPaginasColor = "";
public String tipoEncuadernacion = "fresado"; // enum name public String tipoEncuadernacion = "fresado"; // enum name
public String entregaTipo = "peninsula"; // enum name
public boolean ivaReducido = true; public boolean ivaReducido = true;
} }
@ -157,7 +156,6 @@ public class PresupuestoFormDataMapper {
vm.datosGenerales.tipoEncuadernacion = enumName(p.getTipoEncuadernacion(), "fresado"); vm.datosGenerales.tipoEncuadernacion = enumName(p.getTipoEncuadernacion(), "fresado");
vm.datosGenerales.entregaTipo = enumName(p.getEntregaTipo(), "peninsula");
vm.datosGenerales.ivaReducido = Boolean.TRUE.equals(p.getIvaReducido()); vm.datosGenerales.ivaReducido = Boolean.TRUE.equals(p.getIvaReducido());
// ===== Interior // ===== Interior

View File

@ -329,7 +329,7 @@ public class PresupuestoService {
.filter(Objects::nonNull) .filter(Objects::nonNull)
.map(tirada -> tirada + 4) .map(tirada -> tirada + 4)
.collect(Collectors.toList())); .collect(Collectors.toList()));
if(presupuesto.getSelectedTirada() != null) { if (presupuesto.getSelectedTirada() != null) {
presupuesto.setSelectedTirada(presupuesto.getSelectedTirada()); presupuesto.setSelectedTirada(presupuesto.getSelectedTirada());
} }
} else { } else {
@ -352,7 +352,7 @@ public class PresupuestoService {
body.put("cubierta", cubierta); body.put("cubierta", cubierta);
body.put("guardas", null); body.put("guardas", null);
// Para las reimpresiones // Para las reimpresiones
if(presupuesto.getIsReimpresion() != null && presupuesto.getIsReimpresion()) { if (presupuesto.getIsReimpresion() != null && presupuesto.getIsReimpresion()) {
body.put("reimpresion", 1); body.put("reimpresion", 1);
body.put("iskn", presupuesto.getProveedorRef1()); body.put("iskn", presupuesto.getProveedorRef1());
} }
@ -1126,7 +1126,7 @@ public class PresupuestoService {
if (s.get("id").equals("retractilado")) { if (s.get("id").equals("retractilado")) {
String p = obtenerPrecioRetractilado(cantidad); String p = obtenerPrecioRetractilado(cantidad);
if(p != null){ if (p != null) {
double precio_retractilado = Double.parseDouble(p); double precio_retractilado = Double.parseDouble(p);
s.put("price", precio_retractilado); s.put("price", precio_retractilado);
} else { } else {
@ -1149,7 +1149,7 @@ public class PresupuestoService {
} }
} }
try { try {
if(presupuesto.getSelectedTirada() != null && presupuesto.getSelectedTirada().equals(tirada)) if (presupuesto.getSelectedTirada() != null && presupuesto.getSelectedTirada().equals(tirada))
presupuesto.setServiciosJson(new ObjectMapper().writeValueAsString(servicios)); presupuesto.setServiciosJson(new ObjectMapper().writeValueAsString(servicios));
} catch (Exception ignore) { } catch (Exception ignore) {
System.out.println("Error guardando servicios JSON: " + ignore.getMessage()); System.out.println("Error guardando servicios JSON: " + ignore.getMessage());
@ -1162,7 +1162,6 @@ public class PresupuestoService {
// Si la entrega es en peninsula, se mira el valor del iva // Si la entrega es en peninsula, se mira el valor del iva
// Canarias y paises UE no llevan IVA // Canarias y paises UE no llevan IVA
if (presupuesto.getEntregaTipo() == Presupuesto.Entrega.peninsula) {
// Si el iva es reducido, el precio de la tirada y el del prototipo llevan IVA // Si el iva es reducido, el precio de la tirada y el del prototipo llevan IVA
// 4% // 4%
if (presupuesto.getIvaReducido()) { if (presupuesto.getIvaReducido()) {
@ -1177,7 +1176,6 @@ public class PresupuestoService {
BigDecimal.valueOf(100), 2, BigDecimal.valueOf(100), 2,
RoundingMode.HALF_UP); RoundingMode.HALF_UP);
} }
}
baseImponible = baseImponible.add(serviciosTotal); baseImponible = baseImponible.add(serviciosTotal);
BigDecimal totalConIva = baseImponible.add(ivaImporte21).add(ivaImporte4); BigDecimal totalConIva = baseImponible.add(ivaImporte21).add(ivaImporte4);
@ -1335,7 +1333,7 @@ public class PresupuestoService {
public Boolean hasMaquetacion(Presupuesto presupuesto) { public Boolean hasMaquetacion(Presupuesto presupuesto) {
if (presupuesto.getServiciosJson() != null && !presupuesto.getServiciosJson().isEmpty()) { if (presupuesto.getServiciosJson() != null && !presupuesto.getServiciosJson().isEmpty()) {
if(presupuesto.getServiciosJson().contains("maquetacion")) { if (presupuesto.getServiciosJson().contains("maquetacion")) {
return true; return true;
} }
} }
@ -1474,7 +1472,6 @@ public class PresupuestoService {
target.setServiciosTotal(src.getServiciosTotal()); target.setServiciosTotal(src.getServiciosTotal());
target.setBaseImponible(src.getBaseImponible()); target.setBaseImponible(src.getBaseImponible());
target.setIvaReducido(src.getIvaReducido()); target.setIvaReducido(src.getIvaReducido());
target.setEntregaTipo(src.getEntregaTipo());
target.setIvaImporte4(src.getIvaImporte4()); target.setIvaImporte4(src.getIvaImporte4());
target.setIvaImporte21(src.getIvaImporte21()); target.setIvaImporte21(src.getIvaImporte21());
target.setTotalConIva(src.getTotalConIva()); target.setTotalConIva(src.getTotalConIva());

View File

@ -0,0 +1,20 @@
databaseChangeLog:
- changeSet:
id: 0026-drop-entrega-tipo-from-presupuesto
author: jjo
changes:
- dropColumn:
tableName: presupuesto
columnName: entrega_tipo
rollback:
- addColumn:
tableName: presupuesto
columns:
- column:
name: entrega_tipo
type: ENUM('peninsula', 'canarias', 'paises_ue')
defaultValue: peninsula
afterColumn: base_imponible
constraints:
nullable: false

View File

@ -49,3 +49,5 @@ databaseChangeLog:
file: db/changelog/changesets/0024-series-facturacion-seeder.yml file: db/changelog/changesets/0024-series-facturacion-seeder.yml
- include: - include:
file: db/changelog/changesets/0025-create-facturas-direcciones.yml file: db/changelog/changesets/0025-create-facturas-direcciones.yml
- include:
file: db/changelog/changesets/0026-drop-entrega-tipo-from-presupuesto.yml

View File

@ -18,8 +18,8 @@ $(() => {
$('#addBillingAddressBtn').on('click', seleccionarDireccionEnvio); $('#addBillingAddressBtn').on('click', seleccionarDireccionEnvio);
$('#authorization-required').on('change', function () { $(document).on('change', '#authorization-required', function () {
if($(this).is(':checked')) { if ($(this).is(':checked')) {
if ($('#direccion-div .direccion-card').length > 0) { if ($('#direccion-div .direccion-card').length > 0) {
$('#btn-checkout').prop('disabled', false); $('#btn-checkout').prop('disabled', false);
} }
@ -148,6 +148,22 @@ $(() => {
$('#btn-checkout').prop('disabled', false); $('#btn-checkout').prop('disabled', false);
} }
hideLoader(); hideLoader();
if (direccionId) {
$.ajax({
url: `/checkout/get-summary/${direccionId}`,
type: 'GET',
success: function (response) {
const parent = $('.cart-summary-container').parent();
$('.cart-summary-container').remove();
parent.append(response);
},
error: function () {
console.error('Error al actualizar el resumen del carrito.');
}
});
}
return true; return true;
} }
hideLoader(); hideLoader();
@ -164,6 +180,18 @@ $(() => {
$card.remove(); $card.remove();
$('#addBillingAddressBtn').removeClass('d-none'); $('#addBillingAddressBtn').removeClass('d-none');
$('#btn-checkout').prop('disabled', true); $('#btn-checkout').prop('disabled', true);
$.ajax({
url: `/checkout/get-summary`,
type: 'GET',
success: function (response) {
const parent = $('.cart-summary-container').parent();
$('.cart-summary-container').remove();
parent.append(response);
},
error: function () {
console.error('Error al actualizar el resumen del carrito.');
}
});
}); });
@ -194,7 +222,7 @@ $(() => {
type: 'POST', // PUT simulado via _method type: 'POST', // PUT simulado via _method
data: $form.serialize(), data: $form.serialize(),
dataType: 'html', dataType: 'html',
success: function (html) { success: async function (html) {
// Si por cualquier motivo llega 200 con fragmento, lo insertamos igual // Si por cualquier motivo llega 200 con fragmento, lo insertamos igual
if (typeof html === 'string' && html.indexOf('id="direccionForm"') !== -1 && html.indexOf('<html') === -1) { if (typeof html === 'string' && html.indexOf('id="direccionForm"') !== -1 && html.indexOf('<html') === -1) {
$('#direccionFormModalBody').html(html); $('#direccionFormModalBody').html(html);
@ -205,7 +233,8 @@ $(() => {
} }
// Éxito real: cerrar y recargar tabla // Éxito real: cerrar y recargar tabla
$('#direccionFormModal').modal('hide'); $('#direccionFormModal').modal('hide');
seleccionarDireccionEnvio(); await seleccionarDireccionEnvio();
}, },
error: function (xhr) { error: function (xhr) {
// Con 422 devolvemos el fragmento con errores aquí // Con 422 devolvemos el fragmento con errores aquí

View File

@ -34,7 +34,6 @@ export default class PresupuestoWizard {
paginasColor: 0, paginasColor: 0,
posicionPaginasColor: '', posicionPaginasColor: '',
tipoEncuadernacion: 'fresado', tipoEncuadernacion: 'fresado',
entregaTipo: 'peninsula',
ivaReducido: true, ivaReducido: true,
}, },
interior: { interior: {
@ -130,7 +129,6 @@ export default class PresupuestoWizard {
this.divPosicionPaginasColor = $('#div-posicion-paginas-color'); this.divPosicionPaginasColor = $('#div-posicion-paginas-color');
this.posicionPaginasColor = $('#posicionPaginasColor'); this.posicionPaginasColor = $('#posicionPaginasColor');
this.paginas = $('#paginas'); this.paginas = $('#paginas');
this.entregaTipo = $('#entregaTipo');
this.ivaReducido = $('#iva-reducido'); this.ivaReducido = $('#iva-reducido');
this.btnIvaReducidoDetail = $('#btn-iva-reducido-detail'); this.btnIvaReducidoDetail = $('#btn-iva-reducido-detail');
this.datos_generales_alert = $('#datos-generales-alert'); this.datos_generales_alert = $('#datos-generales-alert');
@ -666,7 +664,6 @@ export default class PresupuestoWizard {
paginasColor: this.paginasColor.val(), paginasColor: this.paginasColor.val(),
posicionPaginasColor: this.posicionPaginasColor.val(), posicionPaginasColor: this.posicionPaginasColor.val(),
tipoEncuadernacion: $('.tipo-libro input:checked').val() || 'fresado', tipoEncuadernacion: $('.tipo-libro input:checked').val() || 'fresado',
entregaTipo: this.entregaTipo.val(),
ivaReducido: this.ivaReducido.is(':checked'), ivaReducido: this.ivaReducido.is(':checked'),
}; };
} }
@ -688,7 +685,6 @@ export default class PresupuestoWizard {
paginasColor: data.paginasColor, paginasColor: data.paginasColor,
posicionPaginasColor: data.posicionPaginasColor, posicionPaginasColor: data.posicionPaginasColor,
tipoEncuadernacion: data.tipoEncuadernacion, tipoEncuadernacion: data.tipoEncuadernacion,
entregaTipo: data.entregaTipo,
ivaReducido: data.ivaReducido, ivaReducido: data.ivaReducido,
}; };
} }
@ -736,7 +732,6 @@ export default class PresupuestoWizard {
} }
} }
this.entregaTipo.val(this.formData.datosGenerales.entregaTipo);
this.ivaReducido.prop('checked', this.formData.datosGenerales.ivaReducido); this.ivaReducido.prop('checked', this.formData.datosGenerales.ivaReducido);
} }

View File

@ -302,19 +302,6 @@
</label> </label>
</div> </div>
</div> </div>
<div class="row justify-content-center mb-2">
<div class="col-sm-3 justify-content-center">
<label for="entregaTipo" class="form-label mt-2"
th:text="#{presupuesto.entrega}">Entrega</label>
<select class="form-select select2 datos-generales-data" id="entregaTipo" name="entregaTipo">
<option selected value="peninsula" th:text="#{presupuesto.entrega.peninsula}">Península
y
Baleares</option>
<option value="canarias" th:text="#{presupuesto.entrega.canarias}">Canarias</option>
<option value="paises_ue" th:text="#{presupuesto.entrega.paises-ue}">Países UE</option>
</select>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>