trabajando en la vista del pedido

This commit is contained in:
2025-11-18 21:32:16 +01:00
parent 997741c3c9
commit 58f0eee5d9
16 changed files with 7360 additions and 6093 deletions

13139
logs/erp.log

File diff suppressed because it is too large Load Diff

View File

@ -34,7 +34,6 @@ public class CartService {
private final CartItemRepository itemRepo; private final CartItemRepository itemRepo;
private final MessageSource messageSource; private final MessageSource messageSource;
private final PresupuestoRepository presupuestoRepo; private final PresupuestoRepository presupuestoRepo;
private final Utils utils;
private final DireccionService direccionService; private final DireccionService direccionService;
private final skApiClient skApiClient; private final skApiClient skApiClient;
private final PedidoService pedidoService; private final PedidoService pedidoService;
@ -43,14 +42,13 @@ public class CartService {
public CartService(CartRepository cartRepo, CartItemRepository itemRepo, public CartService(CartRepository cartRepo, CartItemRepository itemRepo,
CartDireccionRepository cartDireccionRepo, MessageSource messageSource, CartDireccionRepository cartDireccionRepo, MessageSource messageSource,
PresupuestoFormatter presupuestoFormatter, PresupuestoRepository presupuestoRepo, PresupuestoFormatter presupuestoFormatter, PresupuestoRepository presupuestoRepo,
Utils utils, DireccionService direccionService, skApiClient skApiClient, DireccionService direccionService, skApiClient skApiClient,
PedidoService pedidoService, PresupuestoService presupuestoService) { PedidoService pedidoService, PresupuestoService presupuestoService) {
this.cartRepo = cartRepo; this.cartRepo = cartRepo;
this.itemRepo = itemRepo; this.itemRepo = itemRepo;
this.cartDireccionRepo = cartDireccionRepo; this.cartDireccionRepo = cartDireccionRepo;
this.messageSource = messageSource; this.messageSource = messageSource;
this.presupuestoRepo = presupuestoRepo; this.presupuestoRepo = presupuestoRepo;
this.utils = utils;
this.direccionService = direccionService; this.direccionService = direccionService;
this.skApiClient = skApiClient; this.skApiClient = skApiClient;
this.pedidoService = pedidoService; this.pedidoService = pedidoService;
@ -89,7 +87,7 @@ public class CartService {
Presupuesto p = item.getPresupuesto(); Presupuesto p = item.getPresupuesto();
Map<String, Object> elemento = getElementoCart(p, locale); Map<String, Object> elemento = presupuestoService.getPresupuestoInfoForCard(p, locale);
elemento.put("cartItemId", item.getId()); elemento.put("cartItemId", item.getId());
resultados.add(elemento); resultados.add(elemento);
} }
@ -159,38 +157,6 @@ public class CartService {
return itemRepo.findByCartId(cart.getId()).size(); return itemRepo.findByCartId(cart.getId()).size();
} }
private Map<String, Object> getElementoCart(Presupuesto presupuesto, Locale locale) {
Map<String, Object> resumen = new HashMap<>();
resumen.put("titulo", presupuesto.getTitulo());
resumen.put("imagen",
"/assets/images/imprimelibros/presupuestador/" + presupuesto.getTipoEncuadernacion() + ".png");
resumen.put("imagen_alt",
messageSource.getMessage("presupuesto." + presupuesto.getTipoEncuadernacion(), null, locale));
resumen.put("presupuestoId", presupuesto.getId());
if (presupuesto.getServiciosJson() != null && presupuesto.getServiciosJson().contains("ejemplar-prueba")) {
resumen.put("hasSample", true);
} else {
resumen.put("hasSample", false);
}
Map<String, Object> detalles = utils.getTextoPresupuesto(presupuesto, locale);
resumen.put("tirada", presupuesto.getSelectedTirada());
resumen.put("baseTotal", Utils.formatCurrency(presupuesto.getBaseImponible(), locale));
resumen.put("base", presupuesto.getBaseImponible());
resumen.put("iva4", presupuesto.getIvaImporte4());
resumen.put("iva21", presupuesto.getIvaImporte21());
resumen.put("resumen", detalles);
return resumen;
}
public Map<String, Object> getCartSummaryRaw(Cart cart, Locale locale) { public Map<String, Object> getCartSummaryRaw(Cart cart, Locale locale) {
double base = 0.0; double base = 0.0;

View File

@ -361,6 +361,14 @@ public class Utils {
return dateTime.format(formatter); return dateTime.format(formatter);
} }
public static String formatDate(LocalDateTime dateTime, Locale locale) {
if (dateTime == null) {
return "";
}
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy", locale);
return dateTime.format(formatter);
}
public static String formatInstant(Instant instant, Locale locale) { public static String formatInstant(Instant instant, Locale locale) {
if (instant == null) { if (instant == null) {
return ""; return "";

View File

@ -229,6 +229,7 @@ public class skApiClient {
Long id = ((Integer) responseBody.get("id")).longValue(); Long id = ((Integer) responseBody.get("id")).longValue();
if (success != null && id != null && success) { if (success != null && id != null && success) {
return Map.of("data", id); return Map.of("data", id);
} else { } else {
// Tu lógica actual: si success es true u otra cosa → error 2 // Tu lógica actual: si success es true u otra cosa → error 2

View File

@ -52,6 +52,9 @@ public class PedidoLinea {
@Column(name = "estado_manual", nullable = false) @Column(name = "estado_manual", nullable = false)
private Boolean estadoManual; private Boolean estadoManual;
@Column(name = "fecha_entrega")
private LocalDateTime fechaEntrega;
@Column(name = "created_at") @Column(name = "created_at")
private LocalDateTime createdAt; private LocalDateTime createdAt;
@ -100,6 +103,14 @@ public class PedidoLinea {
this.estadoManual = estadoManual; this.estadoManual = estadoManual;
} }
public LocalDateTime getFechaEntrega() {
return fechaEntrega;
}
public void setFechaEntrega(LocalDateTime fechaEntrega) {
this.fechaEntrega = fechaEntrega;
}
public LocalDateTime getCreatedAt() { public LocalDateTime getCreatedAt() {
return createdAt; return createdAt;
} }

View File

@ -9,6 +9,7 @@ import java.util.List;
public interface PedidoLineaRepository extends JpaRepository<PedidoLinea, Long> { public interface PedidoLineaRepository extends JpaRepository<PedidoLinea, Long> {
List<PedidoLinea> findByPedidoId(Long pedidoId); List<PedidoLinea> findByPedidoId(Long pedidoId);
List<PedidoLinea> findByPedidoIdOrderByIdAsc(Long pedidoId);
List<PedidoLinea> findByPresupuestoId(Long presupuestoId); List<PedidoLinea> findByPresupuestoId(Long presupuestoId);
} }

View File

@ -1,6 +1,6 @@
package com.imprimelibros.erp.pedidos; package com.imprimelibros.erp.pedidos;
import java.time.LocalDateTime; import java.time.Instant;
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;
@ -19,5 +19,5 @@ public interface PedidoRepository extends JpaRepository<Pedido, Long>, JpaSpecif
AND p.createdAt >= :afterDate AND p.createdAt >= :afterDate
""") """)
Double sumTotalByCreatedByAndCreatedAtAfter(@Param("userId") Long userId, Double sumTotalByCreatedByAndCreatedAtAfter(@Param("userId") Long userId,
@Param("afterDate") LocalDateTime afterDate); @Param("afterDate") Instant afterDate);
} }

View File

@ -2,8 +2,10 @@ package com.imprimelibros.erp.pedidos;
import java.time.Instant; import java.time.Instant;
import java.time.LocalDateTime; import java.time.LocalDateTime;
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.Map; import java.util.Map;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -44,7 +46,7 @@ public class PedidoService {
public int getDescuentoFidelizacion(Long userId) { public int getDescuentoFidelizacion(Long userId) {
// descuento entre el 1% y el 6% para clientes fidelidad (mas de 1500€ en el // descuento entre el 1% y el 6% para clientes fidelidad (mas de 1500€ en el
// ultimo año) // ultimo año)
LocalDateTime haceUnAno = LocalDateTime.now().minusYears(1); Instant haceUnAno = Instant.now().minusSeconds(365 * 24 * 60 * 60);
double totalGastado = pedidoRepository.sumTotalByCreatedByAndCreatedAtAfter(userId, haceUnAno); double totalGastado = pedidoRepository.sumTotalByCreatedByAndCreatedAtAfter(userId, haceUnAno);
if (totalGastado < 1200) { if (totalGastado < 1200) {
return 0; return 0;
@ -127,6 +129,32 @@ public class PedidoService {
return saved; return saved;
} }
/** Lista de los items del pedido preparados para la vista*/
@Transactional
public List<Map<String, Object>> getLineas(Long pedidoId, Locale locale) {
Pedido p = pedidoRepository.findById(pedidoId).orElse(null);
if (p == null) {
return new ArrayList<>();
}
List<Map<String, Object>> resultados = new ArrayList<>();
List<PedidoLinea> items = pedidoLineaRepository.findByPedidoIdOrderByIdAsc(p.getId());
for (PedidoLinea item : items) {
Presupuesto presupuesto = item.getPresupuesto();
Map<String, Object> elemento = presupuestoService.getPresupuestoInfoForCard(presupuesto, locale);
elemento.put("estado", item.getEstado());
elemento.put("fechaEntrega", item.getFechaEntrega() != null ?
Utils.formatDate(item.getFechaEntrega(), locale) : "");
elemento.put("lineaId", item.getId());
resultados.add(elemento);
}
return resultados;
}
/***************************
* MÉTODOS PRIVADOS
***************************/
@Transactional @Transactional
private void saveDireccionesPedidoLinea( private void saveDireccionesPedidoLinea(
Map<String, Map<String, Object>> direcciones, Map<String, Map<String, Object>> direcciones,

View File

@ -1,6 +1,7 @@
package com.imprimelibros.erp.pedidos; package com.imprimelibros.erp.pedidos;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import java.security.Principal; import java.security.Principal;
@ -12,6 +13,7 @@ import java.util.Map;
import org.springframework.context.MessageSource; import org.springframework.context.MessageSource;
import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import com.imprimelibros.erp.common.Utils; import com.imprimelibros.erp.common.Utils;
import com.imprimelibros.erp.datatables.DataTable; import com.imprimelibros.erp.datatables.DataTable;
@ -31,13 +33,15 @@ import org.springframework.web.bind.annotation.ResponseBody;
public class PedidosController { public class PedidosController {
private final PedidoRepository repoPedido; private final PedidoRepository repoPedido;
private final PedidoService pedidoService;
private final UserDao repoUser; private final UserDao repoUser;
private final MessageSource messageSource; private final MessageSource messageSource;
private final PedidoLineaRepository repoPedidoLinea; private final PedidoLineaRepository repoPedidoLinea;
public PedidosController(PedidoRepository repoPedido, UserDao repoUser, MessageSource messageSource, public PedidosController(PedidoRepository repoPedido, PedidoService pedidoService, UserDao repoUser, MessageSource messageSource,
PedidoLineaRepository repoPedidoLinea) { PedidoLineaRepository repoPedidoLinea) {
this.repoPedido = repoPedido; this.repoPedido = repoPedido;
this.pedidoService = pedidoService;
this.repoUser = repoUser; this.repoUser = repoUser;
this.messageSource = messageSource; this.messageSource = messageSource;
this.repoPedidoLinea = repoPedidoLinea; this.repoPedidoLinea = repoPedidoLinea;
@ -162,4 +166,21 @@ public class PedidosController {
} }
@GetMapping("/view/{id}")
public String verPedido(
@PathVariable(name = "id", required = true) Long id,
Model model, Locale locale) {
Boolean isAdmin = Utils.isCurrentUserAdmin();
if (isAdmin) {
model.addAttribute("isAdmin", true);
} else {
model.addAttribute("isAdmin", false);
}
List<Map<String, Object>> lineas = pedidoService.getLineas(id, locale);
model.addAttribute("lineas", lineas);
model.addAttribute("id", id);
return "imprimelibros/pedidos/pedidos-view";
}
} }

View File

@ -22,6 +22,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import com.imprimelibros.erp.common.Utils;
import com.imprimelibros.erp.common.web.IpUtils; import com.imprimelibros.erp.common.web.IpUtils;
import com.imprimelibros.erp.configurationERP.VariableService; import com.imprimelibros.erp.configurationERP.VariableService;
import com.imprimelibros.erp.presupuesto.GeoIpService; import com.imprimelibros.erp.presupuesto.GeoIpService;
@ -71,14 +72,16 @@ public class PresupuestoService {
private final skApiClient apiClient; private final skApiClient apiClient;
private final GeoIpService geoIpService; private final GeoIpService geoIpService;
private final UserDao userRepo; private final UserDao userRepo;
private final Utils utils;
public PresupuestoService(PresupuestadorItems presupuestadorItems, PresupuestoFormatter presupuestoFormatter, public PresupuestoService(PresupuestadorItems presupuestadorItems, PresupuestoFormatter presupuestoFormatter,
skApiClient apiClient, GeoIpService geoIpService, UserDao userRepo) { skApiClient apiClient, GeoIpService geoIpService, UserDao userRepo, Utils utils) {
this.presupuestadorItems = presupuestadorItems; this.presupuestadorItems = presupuestadorItems;
this.presupuestoFormatter = presupuestoFormatter; this.presupuestoFormatter = presupuestoFormatter;
this.apiClient = apiClient; this.apiClient = apiClient;
this.geoIpService = geoIpService; this.geoIpService = geoIpService;
this.userRepo = userRepo; this.userRepo = userRepo;
this.utils = utils;
} }
public boolean validateDatosGenerales(int[] tiradas) { public boolean validateDatosGenerales(int[] tiradas) {
@ -1321,6 +1324,39 @@ public class PresupuestoService {
return false; return false;
} }
public Map<String, Object> getPresupuestoInfoForCard(Presupuesto presupuesto, Locale locale) {
Map<String, Object> resumen = new HashMap<>();
resumen.put("titulo", presupuesto.getTitulo());
resumen.put("imagen",
"/assets/images/imprimelibros/presupuestador/" + presupuesto.getTipoEncuadernacion() + ".png");
resumen.put("imagen_alt",
messageSource.getMessage("presupuesto." + presupuesto.getTipoEncuadernacion(), null, locale));
resumen.put("presupuestoId", presupuesto.getId());
if (presupuesto.getServiciosJson() != null && presupuesto.getServiciosJson().contains("ejemplar-prueba")) {
resumen.put("hasSample", true);
} else {
resumen.put("hasSample", false);
}
Map<String, Object> detalles = utils.getTextoPresupuesto(presupuesto, locale);
resumen.put("tirada", presupuesto.getSelectedTirada());
resumen.put("baseTotal", Utils.formatCurrency(presupuesto.getBaseImponible(), locale));
resumen.put("base", presupuesto.getBaseImponible());
resumen.put("iva4", presupuesto.getIvaImporte4());
resumen.put("iva21", presupuesto.getIvaImporte21());
resumen.put("total", Utils.formatCurrency(presupuesto.getTotalConIva(), locale));
resumen.put("resumen", detalles);
return resumen;
}
// ======================================================================= // =======================================================================
// Métodos privados // Métodos privados
// ======================================================================= // =======================================================================

View File

@ -0,0 +1,19 @@
databaseChangeLog:
- changeSet:
id: add-fecha-entrega-to-pedidos-lineas
author: jjo
changes:
- addColumn:
tableName: pedidos_lineas
columns:
- column:
name: fecha_entrega
type: datetime
constraints:
nullable: true
afterColumn: estado_manual
rollback:
- dropColumn:
tableName: pedidos_lineas
columnName: fecha_entrega

View File

@ -30,4 +30,6 @@ databaseChangeLog:
- include: - include:
file: db/changelog/changesets/0015-alter-pedidos-lineas-and-presupuesto-estados.yml file: db/changelog/changesets/0015-alter-pedidos-lineas-and-presupuesto-estados.yml
- include: - include:
file: db/changelog/changesets/0016-fix-enum-estado-pedidos-lineas.yml file: db/changelog/changesets/0016-fix-enum-estado-pedidos-lineas.yml
- include:
file: db/changelog/changesets/0017-add-fecha-entrega-to-pedidos-lineas.yml

View File

@ -25,10 +25,15 @@ pedido.estado.terminado=Terminado
pedido.estado.cancelado=Cancelado pedido.estado.cancelado=Cancelado
pedido.module-title=Pedidos pedido.module-title=Pedidos
pedido.pedido=Pedido
pedido.fecha-entrega=Fecha de entrega
pedido.table.id=Num. Pedido pedido.table.id=Num. Pedido
pedido.table.cliente=Cliente pedido.table.cliente=Cliente
pedido.table.fecha=Fecha pedido.table.fecha=Fecha
pedido.table.importe=Importe pedido.table.importe=Importe
pedido.table.estado=Estado pedido.table.estado=Estado
pedido.table.acciones=Acciones pedido.table.acciones=Acciones
pedido.view.tirada=Tirada
pedido.view.view-presupuesto=Ver presupuesto

View File

@ -1,4 +1,8 @@
$(()=>{ $(() => {
$(document,'.btn-view').on('click', function () { $(document).on('click', '.btn-view', function () {
let pedidoId = $(this).data('id');
let url = `/pedidos/view/${pedidoId}`;
window.location.href = url;
}); });
}) })

View File

@ -1,30 +1,93 @@
<div th:fragment="pedido-linea (linea)"> <div th:fragment="pedido-linea (item, isAdmin)">
<div class="row"> <div class="mb-3">
<div class="col-12"> <div class="card p-3 mb-0">
<div class="card mb-3"> <div class="row g-3 align-items-start">
<div class="card-header"> <!-- Col 1: imagen -->
<strong th:text="${linea.libro.titulo}">Título del libro</strong> <div class="col-auto">
<span class="text-muted" th:text="' - ' + #{pedido.linea.cantidad} + ': ' + ${linea.cantidad}"> - Cantidad: 1</span> <div class="avatar-lg bg-light rounded p-1">
<img th:src="${item.imagen != null ? item.imagen : '/assets/images/products/placeholder.png'}"
alt="portada" class="img-fluid d-block rounded">
</div>
</div> </div>
<div class="card-body">
<div class="row"> <!-- Col 2: detalles -->
<div class="col-md-8"> <div class="col">
<p> <h5 class="fs-18 text-truncate mb-1">
<strong th:text="#{pedido.linea.precio-unitario} + ': '"></strong> <span class="text-dark"
<span th:text="${#numbers.formatDecimal(linea.precioUnitario, 1, 'COMMA', 2, 'POINT')} + ' €'">10,00 €</span> th:text="${item.titulo != null ? item.titulo : 'Presupuesto #'}">Presupuesto</span>
</p> </h5>
<p> <h5 class="fs-14 text-truncate mb-1">
<strong th:text="#{pedido.linea.precio-total} + ': '"></strong> <span th:text="#{cart.item.presupuesto-numero}">Presupuesto #</span>
<span th:text="${#numbers.formatDecimal(linea.precioTotal, 1, 'COMMA', 2, 'POINT')} + ' €'">10,00 €</span> <span th:text="${item.presupuestoId != null ? item.presupuestoId : ''}">#</span>
</p> <a th:href="@{|/presupuesto/edit/${item.presupuestoId}|}"
</div> th:text="#{pedido.view.view-presupuesto}" class="badge bg-secondary">Ver presupuesto</a>
<div class="col-md-4 text-end"> </h5>
<img th:if="${linea.libro.imagenPortadaUrl != null}" th:src="${linea.libro.imagenPortadaUrl}" alt="Portada del libro" class="img-fluid" style="max-height: 150px;" />
<div th:if="${linea.libro.imagenPortadaUrl == null}" class="text-muted" style="height: 150px; display: flex; align-items: center; justify-content: center; border: 1px dashed #ccc;"> <ul class="list-unstyled text-muted mb-1 ps-0">
<span th:text="#{pedido.linea.sin-imagen}">Sin imagen</span> <li th:each="linea : ${item.resumen.lineas}" class="mb-1">
</div> <span th:utext="${linea['descripcion']}"></span>
</li>
</ul>
<ul class="list-unstyled text-muted mb-1" th:if="${item.resumen.servicios != null}">
<li>
<span th:utext="#{pdf.servicios-adicionales}">Servicios adicionales:</span>
<span class="spec-label" th:text="${item.resumen.servicios}"></span>
</li>
</ul>
<ul class="list-unstyled text-muted mb-1"
th:if="${item.resumen != null and #maps.containsKey(item.resumen,'datosMaquetacion') and item.resumen['datosMaquetacion'] != null}">
<li class="spec-row mb-1">
<span th:text="#{pdf.datos-maquetacion}">Datos de maquetación:</span>
<span th:utext="${item.resumen.datosMaquetacion}"></span>
</li>
</ul>
<ul class="list-unstyled text-muted mb-1"
th:if="${item.resumen != null and #maps.containsKey(item.resumen,'datosMarcapaginas') and item.resumen['datosMarcapaginas'] != null}">
<li class="spec-row mb-1">
<span th:text="#{pdf.datos-marcapaginas}">Datos de marcapáginas:</span>
<span th:utext="${item.resumen.datosMarcapaginas}"></span>
</li>
</ul>
</div>
<!-- Col 3: precio -->
<div class="col-auto ms-auto text-end">
<p class="text-muted mb-1" th:text="#{cart.precio}">Precio</p>
<h5 class="fs-14 mb-0">
<span th:text="${item.baseTotal != null ? item.total : '-'}">0,00</span>
</h5>
<p class="text-muted mt-4 mb-1" th:text="#{pedido.table.estado}">Estado</p>
<h5 class="fs-14 mb-0">
<span th:text="${item.estado != null} ?
#{__${'pedido.estado.' + item.estado}__} : '-'">
</span>
</h5>
<th:block th:if="${item.fechaEntrega != null and item.fechaEntrega != ''}">
<p class="text-muted mt-4 mb-1" th:text="#{pedido.fecha-entrega}">Fecha de entrega</p>
<h5 class="fs-14 mb-0">
<span th:text="${item.fechaEntrega}">-</span>
</h5>
</th:block>
</div>
</div>
</div>
<div th:if="${isAdmin}" class="card-footer bg-light p-3">
<div class="row align-items-center gy-3">
<div class="col-sm">
<div class="d-flex flex-wrap my-n1">
<!-- Botón eliminar -->
<div>
<a href="javascript:void(0);" class="d-block text-body p-1 px-2 delete-item"
th:attr="data-cart-item-id=${item.presupuestoId}">
<i class="ri-delete-bin-fill text-muted align-bottom me-1"></i> Eliminar
</a>
</div> </div>
</div> </div>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -23,16 +23,19 @@
<nav aria-label="breadcrumb"> <nav aria-label="breadcrumb">
<ol class="breadcrumb"> <ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/"><i class="ri-home-5-fill"></i></a></li> <li class="breadcrumb-item"><a href="/"><i class="ri-home-5-fill"></i></a></li>
<li class="breadcrumb-item active" aria-current="page" th:text="#{pedido.module-title}"> <li class="breadcrumb-item" aria-current="page" th:text="#{pedido.module-title}"><a
href="/pedidos"></a>
Pedidos</li> Pedidos</li>
<li class="breadcrumb-item active" aria-current="page">
<span th:text="#{pedido.pedido} + ' '">Pedido </span><span th:text="${id}"></span>
</li>
</ol> </ol>
</nav> </nav>
</div> </div>
<div class="container-fluid"> <div class="container-fluid">
<th:block th:each="linea: ${pedidoLinea}"> <th:block th:each="linea: ${lineas}">
<div th:insert="~{imprimelibros/pedidos/pedidos-linea :: pedido-linea (linea=${linea})}"></div> <div th:insert="~{imprimelibros/pedidos/pedidos-linea :: pedido-linea (item=${linea}, isAdmin=${isAdmin})}"></div>
</th:block> </th:block>
</div> </div>
</div> </div>