aceptando ferro

This commit is contained in:
2025-12-27 19:19:17 +01:00
parent 3a00702bb1
commit 61be8d6d3b
10 changed files with 9013 additions and 138 deletions

File diff suppressed because one or more lines are too long

View File

@ -420,12 +420,12 @@ public class skApiClient {
ObjectMapper mapper = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(jsonResponse); JsonNode root = mapper.readTree(jsonResponse);
if (root.get("data") == null || !root.get("data").isInt()) { if (root.get("data") == null) {
throw new RuntimeException( throw new RuntimeException(
"Sin respuesta desde el servidor del proveedor"); "Sin respuesta desde el servidor del proveedor");
} }
String estado = root.get("estado").asText(); String estado = root.get("data").asText();
return Map.of( return Map.of(
"estado", estado); "estado", estado);
@ -436,6 +436,146 @@ public class skApiClient {
} }
} }
public Map<String, Object> getFilesTypes(Long presupuestoId, Locale locale) {
try {
Map<String, Object> result = performWithRetryMap(() -> {
String url = this.skApiUrl + "api/files-presupuesto/" + presupuestoId;
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setBearerAuth(authService.getToken()); // token actualizado
HttpEntity<Void> entity = new HttpEntity<>(headers);
ResponseEntity<String> response = restTemplate.exchange(
url,
HttpMethod.GET,
entity,
String.class);
ObjectMapper mapper = new ObjectMapper();
try {
Map<String, Object> responseBody = mapper.readValue(
response.getBody(),
new TypeReference<Map<String, Object>>() {
});
// Si la API devuelve "error" a nivel raíz
if (responseBody.get("error") != null) {
// Devolvemos un mapa con sólo el error para que el caller decida
return Map.of("error", responseBody.get("error"));
}
Boolean hasError = (Boolean) (responseBody.get("error") == null
|| responseBody.get("error") == "null" ? false : true);
Map<String, Boolean> files = (Map<String, Boolean>) responseBody.get("data");
if (files != null && !hasError) {
return Map.of("data", files);
} else {
// Tu lógica actual: si success es true u otra cosa → error 2
return Map.of("error", 2);
}
} catch (JsonProcessingException e) {
e.printStackTrace();
return Map.of("error", 1);
}
});
if (result.get("error") != null) {
throw new RuntimeException(
messageSource.getMessage("pedido.errors.connecting-server-error", null, locale));
}
Map<String, Object> data = (Map<String, Object>) result.get("data");
return data;
} catch (RuntimeException e) {
throw new RuntimeException(
messageSource.getMessage("pedido.errors.connecting-server-error", null, locale));
}
}
public byte[] downloadFile(Long presupuestoId, String fileType, Locale locale) {
return performWithRetryBytes(() -> {
String normalized = (fileType == null) ? "" : fileType.trim().toLowerCase();
String endpoint = switch (normalized) {
case "ferro" -> "api/get-ferro/" + presupuestoId;
case "cubierta" -> "api/get-cubierta/" + presupuestoId;
case "tapa" -> "api/get-tapa/" + presupuestoId;
default -> throw new IllegalArgumentException("Tipo de fichero no soportado: " + fileType);
};
// OJO: skApiUrl debería terminar en "/" para que concatene bien
String url = this.skApiUrl + endpoint;
HttpHeaders headers = new HttpHeaders();
// Si tu CI4 requiere Bearer, mantenlo. Si NO lo requiere, puedes quitar esta
// línea.
headers.setBearerAuth(authService.getToken());
headers.setAccept(List.of(MediaType.APPLICATION_PDF, MediaType.APPLICATION_OCTET_STREAM));
try {
ResponseEntity<byte[]> response = restTemplate.exchange(
url,
HttpMethod.GET,
new HttpEntity<>(headers),
byte[].class);
if (response.getStatusCode().is2xxSuccessful()) {
return response.getBody(); // bytes del PDF
}
return null;
} catch (HttpClientErrorException.NotFound e) {
// CI4 no tiene ese fichero
return null;
}
});
}
public Boolean aceptarFerro(Long presupuestoId, Locale locale) {
String result = performWithRetry(() -> {
String url = this.skApiUrl + "api/aceptar-ferro/" + presupuestoId;
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setBearerAuth(authService.getToken());
HttpEntity<Void> entity = new HttpEntity<>(headers);
ResponseEntity<String> response = restTemplate.exchange(
url,
HttpMethod.POST,
entity,
String.class);
try {
Map<String, Object> responseBody = new ObjectMapper().readValue(
response.getBody(),
new TypeReference<Map<String, Object>>() {
});
Boolean success = (Boolean) (responseBody.get("success") != null ? responseBody.get("success") : false);
return success.toString();
} catch (JsonProcessingException e) {
e.printStackTrace();
return "false"; // Fallback en caso de error
}
});
return Boolean.parseBoolean(result);
}
/****************** /******************
* PRIVATE METHODS * PRIVATE METHODS
******************/ ******************/
@ -467,6 +607,19 @@ public class skApiClient {
} }
} }
private byte[] performWithRetryBytes(Supplier<byte[]> request) {
try {
return request.get();
} catch (HttpClientErrorException.Unauthorized e) {
authService.invalidateToken();
try {
return request.get();
} catch (HttpClientErrorException ex) {
throw new RuntimeException("La autenticación ha fallado tras renovar el token.", ex);
}
}
}
private static BigDecimal calcularMargen( private static BigDecimal calcularMargen(
BigDecimal importe, BigDecimal importeMin, BigDecimal importeMax, BigDecimal importe, BigDecimal importeMin, BigDecimal importeMax,
BigDecimal margenMax, BigDecimal margenMin) { BigDecimal margenMax, BigDecimal margenMin) {

View File

@ -19,7 +19,8 @@ public class PedidoLinea {
esperando_aceptacion_ferro("pedido.estado.esperando_aceptacion_ferro", 7), esperando_aceptacion_ferro("pedido.estado.esperando_aceptacion_ferro", 7),
ferro_cliente("pedido.estado.ferro_cliente", 8), ferro_cliente("pedido.estado.ferro_cliente", 8),
produccion("pedido.estado.produccion", 9), produccion("pedido.estado.produccion", 9),
cancelado("pedido.estado.cancelado", 10); terminado("pedido.estado.terminado", 10),
cancelado("pedido.estado.cancelado", 11);
private final String messageKey; private final String messageKey;
private final int priority; private final int priority;

View File

@ -8,6 +8,7 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -38,11 +39,13 @@ public class PedidoService {
private final CartService cartService; private final CartService cartService;
private final skApiClient skApiClient; private final skApiClient skApiClient;
private final PresupuestoRepository presupuestoRepo; private final PresupuestoRepository presupuestoRepo;
private final MessageSource messageSource;
public PedidoService(PedidoRepository pedidoRepository, PedidoLineaRepository pedidoLineaRepository, public PedidoService(PedidoRepository pedidoRepository, PedidoLineaRepository pedidoLineaRepository,
PresupuestoRepository presupuestoRepository, PedidoDireccionRepository pedidoDireccionRepository, PresupuestoRepository presupuestoRepository, PedidoDireccionRepository pedidoDireccionRepository,
DireccionService direccionService, UserService userService, PresupuestoService presupuestoService, DireccionService direccionService, UserService userService, PresupuestoService presupuestoService,
CartService cartService, skApiClient skApiClient, PresupuestoRepository presupuestoRepo) { CartService cartService, skApiClient skApiClient, PresupuestoRepository presupuestoRepo,
MessageSource messageSource) {
this.pedidoRepository = pedidoRepository; this.pedidoRepository = pedidoRepository;
this.pedidoLineaRepository = pedidoLineaRepository; this.pedidoLineaRepository = pedidoLineaRepository;
this.presupuestoRepository = presupuestoRepository; this.presupuestoRepository = presupuestoRepository;
@ -53,6 +56,7 @@ public class PedidoService {
this.cartService = cartService; this.cartService = cartService;
this.skApiClient = skApiClient; this.skApiClient = skApiClient;
this.presupuestoRepo = presupuestoRepo; this.presupuestoRepo = presupuestoRepo;
this.messageSource = messageSource;
} }
@Transactional @Transactional
@ -236,14 +240,44 @@ public class PedidoService {
return true; return true;
} }
public Boolean actualizarEstado(Long pedidoId) { public Map<String, Object> actualizarEstado(Long pedidoLineaId, Locale locale) {
Pedido pedido = pedidoRepository.findById(pedidoId).orElse(null); PedidoLinea pedidoLinea = pedidoLineaRepository.findById(pedidoLineaId).orElse(null);
if (pedido == null) { if (pedidoLinea == null) {
return false; return Map.of("success", false,
"message", messageSource.getMessage("pedido.errors.linea-not-found", null, locale));
} }
pedidoRepository.save(pedido); if (pedidoLinea.getEstado().getPriority() >= PedidoLinea.Estado.haciendo_ferro.getPriority() &&
return true; pedidoLinea.getEstado().getPriority() < PedidoLinea.Estado.terminado.getPriority()) {
PedidoLinea.Estado estadoOld = pedidoLinea.getEstado();
Map<String, Object> result = skApiClient.checkPedidoEstado(
Long.valueOf(pedidoLinea.getPresupuesto().getProveedorRef2().toString()), locale);
if (result == null || !result.containsKey("estado")) {
return Map.of(
"success", false,
"message", messageSource.getMessage("pedido.errors.update-server-error", null, locale));
}
PedidoLinea.Estado estadoSk = PedidoLinea.Estado.valueOf((String) result.get("estado"));
if (estadoOld == estadoSk) {
return Map.of(
"success", true,
"state", messageSource.getMessage("pedido.estado." + estadoSk.name(), null, locale),
"stateKey", estadoSk.name(),
"message", messageSource.getMessage("pedido.success.same-estado", null, locale));
}
pedidoLinea.setEstado(estadoSk);
pedidoLineaRepository.save(pedidoLinea);
return Map.of(
"success", true,
"state", messageSource.getMessage("pedido.estado." + estadoSk.name(), null, locale),
"stateKey", estadoSk.name(),
"message", messageSource.getMessage("pedido.success.estado-actualizado", null, locale));
}
return Map.of(
"success", false,
"message", messageSource.getMessage("pedido.errors.cannot-update", null, locale));
} }
public Boolean markPedidoAsMaquetacionDone(Long pedidoId) { public Boolean markPedidoAsMaquetacionDone(Long pedidoId) {
@ -261,11 +295,62 @@ public class PedidoService {
return true; return true;
} }
public Map<String, Object> getFilesType(Long pedidoLineaId, Locale locale) {
PedidoLinea pedidoLinea = pedidoLineaRepository.findById(pedidoLineaId).orElse(null);
if (pedidoLinea == null) {
return Map.of("success", false, "message", "Línea de pedido no encontrada.");
}
Map<String, Object> files = skApiClient.getFilesTypes(
Long.valueOf(pedidoLinea.getPresupuesto().getProveedorRef2().toString()), locale);
return files;
}
public byte[] getFerroFileContent(Long pedidoLineaId, Locale locale) {
return downloadFile(pedidoLineaId, "ferro", locale);
}
public byte[] getCubiertaFileContent(Long pedidoLineaId, Locale locale) {
return downloadFile(pedidoLineaId, "cubierta", locale);
}
public byte[] getTapaFileContent(Long pedidoLineaId, Locale locale) {
return downloadFile(pedidoLineaId, "tapa", locale);
}
public Boolean aceptarFerro(Long pedidoLineaId, Locale locale) {
PedidoLinea pedidoLinea = pedidoLineaRepository.findById(pedidoLineaId).orElse(null);
if (pedidoLinea == null) {
return false;
}
if (pedidoLinea.getEstado() != PedidoLinea.Estado.esperando_aceptacion_ferro) {
return false;
}
Boolean result = skApiClient.aceptarFerro(
Long.valueOf(pedidoLinea.getPresupuesto().getProveedorRef2().toString()), locale);
if (!result) {
return false;
}
pedidoLinea.setEstado(PedidoLinea.Estado.produccion);
pedidoLineaRepository.save(pedidoLinea);
return true;
}
/*************************** /***************************
* MÉTODOS PRIVADOS * MÉTODOS PRIVADOS
***************************/ ***************************/
private byte[] downloadFile(Long pedidoLineaId, String fileType, Locale locale) {
PedidoLinea pedidoLinea = pedidoLineaRepository.findById(pedidoLineaId).orElse(null);
if (pedidoLinea == null) {
return null;
}
byte[] fileData = skApiClient.downloadFile(
Long.valueOf(pedidoLinea.getPresupuesto().getProveedorRef2().toString()),
fileType,
locale);
return fileData;
}
@Transactional @Transactional
private Map<String, Object> savePresupuestoSK(Long pedidoLineaId, Presupuesto presupuesto, Integer counter, private Map<String, Object> savePresupuestoSK(Long pedidoLineaId, Presupuesto presupuesto, Integer counter,
Integer total) { Integer total) {
@ -502,7 +587,6 @@ public class PedidoService {
} }
} }
private PedidoDireccion saveDireccion( private PedidoDireccion saveDireccion(
String email, String email,
Boolean palets, Boolean palets,

View File

@ -4,14 +4,20 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import java.security.Principal; import java.security.Principal;
import java.util.Comparator; import java.util.Comparator;
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 org.springframework.context.MessageSource; import org.springframework.context.MessageSource;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
@ -30,7 +36,8 @@ import jakarta.persistence.criteria.JoinType;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@Controller @Controller
@RequestMapping("/pedidos") @RequestMapping("/pedidos")
@ -66,9 +73,9 @@ public class PedidosController {
"app.cancelar", "app.cancelar",
"app.seleccionar", "app.seleccionar",
"app.yes", "app.yes",
"checkout.payment.card", "checkout.payment.card",
"checkout.payment.bizum", "checkout.payment.bizum",
"checkout.payment.bank-transfer", "checkout.payment.bank-transfer",
"checkout.error.select-method"); "checkout.error.select-method");
Map<String, String> translations = translationService.getTranslations(locale, keys); Map<String, String> translations = translationService.getTranslations(locale, keys);
@ -181,15 +188,17 @@ public class PedidosController {
return text; return text;
}) })
.add("actions", pedido -> { .add("actions", pedido -> {
String data = "<span class=\'badge bg-success btn-view \' data-id=\'" + pedido.getId() String data = "<span class=\'badge bg-success btn-view \' data-id=\'" + pedido.getId()
+ "\' style=\'cursor: pointer;\'>" + "\' style=\'cursor: pointer;\'>"
+ messageSource.getMessage("app.view", null, locale) + "</span>"; + messageSource.getMessage("app.view", null, locale) + "</span>";
List<PedidoLinea> lineas = repoPedidoLinea.findByPedidoId(pedido.getId()); List<PedidoLinea> lineas = repoPedidoLinea.findByPedidoId(pedido.getId());
boolean hasDenegadoPago = lineas.stream() boolean hasDenegadoPago = lineas.stream()
.anyMatch(linea -> PedidoLinea.Estado.denegado_pago.equals(linea.getEstado())); .anyMatch(linea -> PedidoLinea.Estado.denegado_pago.equals(linea.getEstado()));
if (hasDenegadoPago) { if (hasDenegadoPago) {
data += " <span class='badge bg-danger btn-pay' data-amount='" + (int)(pedido.getTotal()*100) + "' data-id='" + pedido.getId() + "' style='cursor: pointer;'>" + messageSource.getMessage("app.pay", null, locale) + "</span>"; data += " <span class='badge bg-danger btn-pay' data-amount='" + (int) (pedido.getTotal() * 100)
} + "' data-id='" + pedido.getId() + "' style='cursor: pointer;'>"
+ messageSource.getMessage("app.pay", null, locale) + "</span>";
}
return data; return data;
}) })
.where(base) .where(base)
@ -219,6 +228,32 @@ public class PedidosController {
List<Map<String, Object>> lineas = pedidoService.getLineas(id, locale); List<Map<String, Object>> lineas = pedidoService.getLineas(id, locale);
for (Map<String, Object> linea : lineas) { for (Map<String, Object> linea : lineas) {
PedidoLinea pedidoLinea = repoPedidoLinea.findById(
((Number) linea.get("lineaId")).longValue()).orElse(null);
if (pedidoLinea != null) {
Map<String, Boolean> buttons = new HashMap<>();
if (pedidoLinea.getEstado().getPriority() >= PedidoLinea.Estado.esperando_aceptacion_ferro.getPriority()
&& pedidoLinea.getEstado().getPriority() <= PedidoLinea.Estado.produccion.getPriority()) {
if (pedidoLinea.getEstado() == PedidoLinea.Estado.esperando_aceptacion_ferro) {
buttons.put("aceptar_ferro", true);
} else {
buttons.put("aceptar_ferro", false);
}
Map<String, Object> filesType = pedidoService.getFilesType(pedidoLinea.getId(), locale);
if (filesType == null || filesType.get("error") != null) {
throw new RuntimeException(
messageSource.getMessage("pedido.errors.update-server-error", null, locale));
}
for (String key : filesType.keySet()) {
buttons.put(key, (Integer) filesType.get(key) == 1 ? true : false);
}
linea.put("buttons", buttons);
}
}
List<PedidoDireccion> dirEntrega = pedidoService.getDireccionesEntregaPedidoLinea( List<PedidoDireccion> dirEntrega = pedidoService.getDireccionesEntregaPedidoLinea(
((Number) linea.get("lineaId")).longValue()); ((Number) linea.get("lineaId")).longValue());
@ -239,15 +274,131 @@ public class PedidosController {
// ------------------------------------- // -------------------------------------
// Acciones sobre las lineas de pedido // Acciones sobre las lineas de pedido
// ------------------------------------- // -------------------------------------
@GetMapping("/linea/{id}/update-status") @PostMapping("/linea/{id}/update-status")
public String getMethodName( @ResponseBody
@PathVariable(name = "id", required = true) Long id) { public Map<String, Object> updateStatus(
@PathVariable(name = "id", required = true) Long id, Locale locale) {
PedidoLinea linea = repoPedidoLinea.findById(id).orElse(null); Map<String, Object> result = pedidoService.actualizarEstado(id, locale);
if (linea != null) {
Long externalId = linea.getPresupuesto().getProveedorRef2(); return result;
}
return new String();
} }
}
@PostMapping("/linea/{id}/update-maquetacion")
@ResponseBody
public Map<String, Object> updateMaquetacion(
@PathVariable(name = "id", required = true) Long id,
Locale locale) {
PedidoLinea entity = repoPedidoLinea.findById(id).orElse(null);
if (entity == null) {
String errorMsg = messageSource.getMessage("pedido.errors.linea-not-found", null, locale);
return Map.of(
"success", false,
"message", errorMsg);
}
if (entity.getEstado() != PedidoLinea.Estado.maquetacion) {
String errorMsg = messageSource.getMessage("pedido.errors.state-error", null, locale);
return Map.of(
"success", false,
"message", errorMsg);
}
entity.setEstado(PedidoLinea.Estado.haciendo_ferro);
repoPedidoLinea.save(entity);
String successMsg = messageSource.getMessage("pedido.success.estado-actualizado", null, locale);
return Map.of(
"success", true,
"message", successMsg,
"state", messageSource.getMessage(entity.getEstado().getMessageKey(), null, locale));
}
@GetMapping("/linea/{id}/download-ferro")
public ResponseEntity<Resource> downloadFerro(@PathVariable(name = "id", required = true) Long id, Locale locale) {
byte[] ferroFileContent = pedidoService.getFerroFileContent(id, locale);
if (ferroFileContent == null) {
return ResponseEntity.notFound().build();
}
ByteArrayResource resource = new ByteArrayResource(ferroFileContent);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=ferro_" + id + ".pdf")
.contentType(MediaType.APPLICATION_PDF)
.body(resource);
}
@GetMapping("/linea/{id}/download-cub")
public ResponseEntity<Resource> downloadCubierta(@PathVariable(name = "id", required = true) Long id,
Locale locale) {
byte[] cubFileContent = pedidoService.getCubiertaFileContent(id, locale);
if (cubFileContent == null) {
return ResponseEntity.notFound().build();
}
ByteArrayResource resource = new ByteArrayResource(cubFileContent);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=cubierta_" + id + ".pdf")
.contentType(MediaType.APPLICATION_PDF)
.body(resource);
}
@GetMapping("/linea/{id}/download-tapa")
public ResponseEntity<Resource> downloadTapa(@PathVariable(name = "id", required = true) Long id, Locale locale) {
byte[] tapaFileContent = pedidoService.getTapaFileContent(id, locale);
if (tapaFileContent == null) {
return ResponseEntity.notFound().build();
}
ByteArrayResource resource = new ByteArrayResource(tapaFileContent);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=tapa_" + id + ".pdf")
.contentType(MediaType.APPLICATION_PDF)
.body(resource);
}
@PostMapping("/linea/{id}/aceptar-ferro")
@ResponseBody
public Map<String, Object> aceptarFerro(@PathVariable(name = "id", required = true) Long id,
Locale locale) {
PedidoLinea entity = repoPedidoLinea.findById(id).orElse(null);
if (entity == null) {
String errorMsg = messageSource.getMessage("pedido.errors.linea-not-found", null, locale);
return Map.of(
"success", false,
"message", errorMsg);
}
if (entity.getEstado() != PedidoLinea.Estado.esperando_aceptacion_ferro) {
String errorMsg = messageSource.getMessage("pedido.errors.state-error", null, locale);
return Map.of(
"success", false,
"message", errorMsg);
}
Boolean result = pedidoService.aceptarFerro(id, locale);
if (result) {
entity.setEstado(PedidoLinea.Estado.haciendo_ferro);
repoPedidoLinea.save(entity);
String successMsg = messageSource.getMessage("pedido.success.estado-actualizado", null, locale);
return Map.of(
"success", true,
"message", successMsg,
"state", messageSource.getMessage(entity.getEstado().getMessageKey(), null, locale));
} else {
String errorMsg = messageSource.getMessage("pedido.errors.update-server-error", null, locale);
return Map.of(
"success", false,
"message", errorMsg);
}
}
}

View File

@ -40,4 +40,6 @@ databaseChangeLog:
- include: - include:
file: db/changelog/changesets/0020-add-estados-pago-to-pedidos-lineas-2.yml file: db/changelog/changesets/0020-add-estados-pago-to-pedidos-lineas-2.yml
- include: - include:
file: db/changelog/changesets/0021-add-email-and-is-palets-to-pedidos-direcciones.yml file: db/changelog/changesets/0021-add-email-and-is-palets-to-pedidos-direcciones.yml
- include:
file: db/changelog/changesets/0022-add-estados-pago-to-pedidos-lineas-3.yml

View File

@ -51,4 +51,16 @@ pedido.table.estado=Estado
pedido.table.acciones=Acciones pedido.table.acciones=Acciones
pedido.view.tirada=Tirada pedido.view.tirada=Tirada
pedido.view.view-presupuesto=Ver presupuesto pedido.view.view-presupuesto=Ver presupuesto
pedido.view.aceptar-ferro=Aceptar ferro
pedido.view.ferro-download=Descargar ferro
pedido.view.cub-download=Descargar cubierta
pedido.view.tapa-download=Descargar tapa
pedido.errors.linea-not-found=No se ha encontrado la línea de pedido.
pedido.errors.state-error=Estado de línea no válido.
pedido.errors.update-server-error=Error al actualizar el estado desde el servidor externo.
pedido.errors.connecting-server-error=Error al conectar con el servidor externo.
pedido.errors.cannot-update=No se puede actualizar el estado de una línea con ese estado inicial.
pedido.success.estado-actualizado=Estado del pedido actualizado correctamente.
pedido.success.same-estado=Sin cambios en el estado.

View File

@ -1,4 +1,4 @@
$(()=>{ $(() => {
const csrfToken = document.querySelector('meta[name="_csrf"]')?.getAttribute('content'); const csrfToken = document.querySelector('meta[name="_csrf"]')?.getAttribute('content');
const csrfHeader = document.querySelector('meta[name="_csrf_header"]')?.getAttribute('content'); const csrfHeader = document.querySelector('meta[name="_csrf_header"]')?.getAttribute('content');
if (window.$ && csrfToken && csrfHeader) { if (window.$ && csrfToken && csrfHeader) {
@ -11,26 +11,131 @@ $(()=>{
const language = document.documentElement.lang || 'es-ES'; const language = document.documentElement.lang || 'es-ES';
$(document).on('click', '.update-status-item', function(){ $(document).on('click', '.update-status-item', function () {
const lineaId = $(this).data('linea-id'); const lineaId = $(this).data('linea-id');
if(!lineaId){ if (!lineaId) {
console.error('No se ha encontrado el ID de la línea del pedido.'); console.error('No se ha encontrado el ID de la línea del pedido.');
return; return;
} }
// Llamada AJAX para actualizar el estado del pedido // Llamada AJAX para actualizar el estado del pedido
$.ajax({ $.ajax({
url: `/imprimelibros/pedidos/linea/${lineaId}/update-status`, url: `/pedidos/linea/${lineaId}/update-status`,
type: 'POST', type: 'POST',
success: function(response) { success: function (response) {
alert('Estado del pedido actualizado correctamente.'); if (!response || !response.success) {
// Aquí puedes agregar lógica adicional, como actualizar la interfaz de usuario Swal.fire({
icon: 'error',
title: response.message || "Error",
timer: 1800,
buttonsStyling: false,
customClass: {
confirmButton: 'btn btn-secondary me-2',
cancelButton: 'btn btn-light'
},
showConfirmButton: false
});
}
else {
const estadoSpan = $(`.estado-linea[data-linea-id='${lineaId}']`);
if (estadoSpan.length) {
estadoSpan.text(response.state);
}
if(response.stateKey === 'terminado' || response.stateKey === 'cancelado') {
$(`.update-estado-button[data-linea-id='${lineaId}']`)
.closest('.update-estado-button')
.addClass('d-none');
}
Swal.fire({
icon: 'success',
title: response.message || "Exito",
timer: 1800,
buttonsStyling: false,
customClass: {
confirmButton: 'btn btn-secondary me-2',
cancelButton: 'btn btn-light'
},
showConfirmButton: false
});
}
}, },
error: function(xhr, status, error) { error: function (xhr, status, error) {
console.error('Error al actualizar el estado del pedido:', error); console.error('Error al actualizar el estado del pedido:', error);
alert('Hubo un error al actualizar el estado del pedido.'); Swal.fire({
icon: 'error',
title: xhr.responseJSON?.message || 'Error',
buttonsStyling: false,
customClass: {
confirmButton: 'btn btn-secondary me-2', // clases para el botón confirmar
cancelButton: 'btn btn-light' // clases para cancelar
}
});
} }
}); });
}); });
$(document).on('click', '.maquetacion-ok', function () {
const lineaId = $(this).data('linea-id');
if (!lineaId) {
console.error('No se ha encontrado el ID de la línea del pedido.');
return;
}
// Llamada AJAX para marcar la maquetación como OK
$.ajax({
url: `/pedidos/linea/${lineaId}/update-maquetacion`,
type: 'POST',
success: function (response) {
if (!response || !response.success) {
Swal.fire({
icon: 'error',
title: response.message || "Error",
timer: 1800,
buttonsStyling: false,
customClass: {
confirmButton: 'btn btn-secondary me-2',
cancelButton: 'btn btn-light'
},
showConfirmButton: false
});
}
else {
const estadoSpan = $(`.estado-linea[data-linea-id='${lineaId}']`);
if (estadoSpan.length) {
estadoSpan.text(response.state);
// hide the maquetacion-ok button
$(`.maquetacion-ok[data-linea-id='${lineaId}']`)
.closest('.maquetacion-ok-button')
.addClass('d-none');
}
Swal.fire({
icon: 'success',
title: response.message || "Exito",
timer: 1800,
buttonsStyling: false,
customClass: {
confirmButton: 'btn btn-secondary me-2',
cancelButton: 'btn btn-light'
},
showConfirmButton: false
});
}
},
error: function (xhr, status, error) {
console.error('Error al actualizar la maquetación del pedido:', error);
Swal.fire({
icon: 'error',
title: xhr.responseJSON?.message || 'Error',
buttonsStyling: false,
customClass: {
confirmButton: 'btn btn-secondary me-2', // clases para el botón confirmar
cancelButton: 'btn btn-light' // clases para cancelar
}
});
}
});
});
}) })

View File

@ -0,0 +1,81 @@
$(() => {
if ($(".btn-download-ferro").length) {
$(document).on('click', '.btn-download-ferro', function () {
const lineaId = $(this).data('linea-id');
window.open(`/pedidos/linea/${lineaId}/download-ferro`, '_blank');
});
}
if ($(".btn-download-cub").length) {
$(document).on('click', '.btn-download-cub', function () {
const lineaId = $(this).data('linea-id');
window.open(`/pedidos/linea/${lineaId}/download-cub`, '_blank');
});
}
if ($(".btn-download-tapa").length) {
$(document).on('click', '.btn-download-tapa', function () {
const lineaId = $(this).data('linea-id');
window.open(`/pedidos/linea/${lineaId}/download-tapa`, '_blank');
});
}
if ($(".btn-aceptar-ferro").length) {
$(document).on('click', '.btn-aceptar-ferro', function () {
const lineaId = $(this).data('linea-id');
$.ajax({
url: `/pedidos/linea/${lineaId}/aceptar-ferro`,
type: 'POST',
success: function (response) {
if (!response || !response.success) {
Swal.fire({
icon: 'error',
title: response.message || "Error",
timer: 1800,
buttonsStyling: false,
customClass: {
confirmButton: 'btn btn-secondary me-2',
cancelButton: 'btn btn-light'
},
showConfirmButton: false
});
}
else {
const estadoSpan = $(`.estado-linea[data-linea-id='${lineaId}']`);
if (estadoSpan.length) {
estadoSpan.text(response.state);
}
$(`.btn-aceptar-ferro[data-linea-id='${lineaId}']`)
.closest('.btn-aceptar-ferro')
.addClass('d-none');
Swal.fire({
icon: 'success',
title: response.message || "Exito",
timer: 1800,
buttonsStyling: false,
customClass: {
confirmButton: 'btn btn-secondary me-2',
cancelButton: 'btn btn-light'
},
showConfirmButton: false
});
}
},
error: function (xhr, status, error) {
console.error('Error al aceptar el ferro del pedido:', error);
Swal.fire({
icon: 'error',
title: xhr.responseJSON?.message || 'Error',
buttonsStyling: false,
customClass: {
confirmButton: 'btn btn-secondary me-2', // clases para el botón confirmar
cancelButton: 'btn btn-light' // clases para cancelar
}
});
}
});
});
}
});

View File

@ -62,10 +62,38 @@
</h5> </h5>
<p class="text-muted mt-4 mb-1" th:text="#{pedido.table.estado}">Estado</p> <p class="text-muted mt-4 mb-1" th:text="#{pedido.table.estado}">Estado</p>
<h5 class="fs-14 mb-0"> <h5 class="fs-14 mb-0">
<span th:text="${item.estado != null} ? <span class="estado-linea" th:attr="data-linea-id=${item.lineaId}" th:text="${item.estado != null} ?
#{__${'pedido.estado.' + item.estado}__} : '-'"> #{__${'pedido.estado.' + item.estado}__} : '-'">
</span> </span>
</h5> </h5>
<div class="col-12 d-grid gap-2 mt-2">
<button th:if="${item.estado.name == 'esperando_aceptacion_ferro'}" type="button"
class="btn btn-secondary w-100 btn-aceptar-ferro" th:text="#{pedido.view.aceptar-ferro}"
th:attr="data-linea-id=${item.lineaId}">
Aceptar ferro
</button>
<button th:if="${item.estado.priority >= 7 && item.estado.priority < 11 && item.buttons.ferro}"
type="button" class="btn btn-light w-100 btn-download-ferro"
th:text="#{pedido.view.ferro-download}"
th:attr="data-linea-id=${item.lineaId}">
Descargar ferro
</button>
<button th:if="${item.estado.priority >= 7 && item.estado.priority < 11 && item.buttons.cub}"
type="button" class="btn btn-light w-100 btn-download-cub"
th:text="#{pedido.view.cub-download}"
th:attr="data-linea-id=${item.lineaId}">
Descargar cubierta
</button>
<button th:if="${item.estado.priority >= 7 && item.estado.priority < 11 && item.buttons.tapa}"
type="button" class="btn btn-light w-100 btn-download-tapa"
th:text="#{pedido.view.tapa-download}"
th:attr="data-linea-id=${item.lineaId}">
Descargar tapa
</button>
</div>
<th:block th:if="${item.fechaEntrega != null and item.fechaEntrega != ''}"> <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> <p class="text-muted mt-4 mb-1" th:text="#{pedido.fecha-entrega}">Fecha de entrega</p>
<h5 class="fs-14 mb-0"> <h5 class="fs-14 mb-0">
@ -88,7 +116,8 @@
</div> </div>
<div class="col"> <div class="col">
<div class="row g-3"> <div class="row g-3">
<div th:each="direccionEnvio : ${item.direccionesEntrega}" class="mb-3 col-xl-4 col-lg-6 col-md-12 col-sm-12"> <div th:each="direccionEnvio : ${item.direccionesEntrega}"
class="mb-3 col-xl-4 col-lg-6 col-md-12 col-sm-12">
<div th:insert="~{imprimelibros/direcciones/direccionEnvioCard :: direccionEnvioCard( <div th:insert="~{imprimelibros/direcciones/direccionEnvioCard :: direccionEnvioCard(
direccion=${direccionEnvio}, direccion=${direccionEnvio},
pais=${direccionEnvio.paisNombre} pais=${direccionEnvio.paisNombre}
@ -106,7 +135,7 @@
<div class="col-sm"> <div class="col-sm">
<div class="d-flex flex-wrap my-n1"> <div class="d-flex flex-wrap my-n1">
<!-- Botón cancelar --> <!-- Botón cancelar -->
<div> <div th:if="${item.estado.name != 'cancelado' && item.estado.name != 'terminado'}">
<a href="javascript:void(0);" class="d-block text-body p-1 px-2 cancel-item" <a href="javascript:void(0);" class="d-block text-body p-1 px-2 cancel-item"
th:attr="data-linea-id=${item.lineaId}"> th:attr="data-linea-id=${item.lineaId}">
<i class="ri-delete-bin-fill text-muted align-bottom me-1"><span <i class="ri-delete-bin-fill text-muted align-bottom me-1"><span
@ -114,14 +143,15 @@
</a> </a>
</div> </div>
<!-- Actualizar estado--> <!-- Actualizar estado-->
<div> <div class="update-estado-button"
th:if="${item.estado.name != 'cancelado' && item.estado.name != 'maquetacion' && item.estado.name != 'terminado'}">
<a href="javascript:void(0);" class="d-block text-body p-1 px-2 update-status-item" <a href="javascript:void(0);" class="d-block text-body p-1 px-2 update-status-item"
th:attr="data-linea-id=${item.lineaId}"> th:attr="data-linea-id=${item.lineaId}">
<i class="ri-refresh-line text-muted align-bottom me-1"><span <i class="ri-refresh-line text-muted align-bottom me-1"><span
th:text="#{pedido.update-estado}">Cancelar Pedido</span></i> th:text="#{pedido.update-estado}">Actualizar estado</span></i>
</a> </a>
</div> </div>
<div th:if="${item.estado == 'maquetacion'}"> <div class="maquetacion-ok-button" th:if="${item.estado.name == 'maquetacion'}">
<a href="javascript:void(0);" class="d-block text-body p-1 px-2 maquetacion-ok" <a href="javascript:void(0);" class="d-block text-body p-1 px-2 maquetacion-ok"
th:attr="data-linea-id=${item.lineaId}"> th:attr="data-linea-id=${item.lineaId}">
<i class="ri-check-double-line text-muted align-bottom me-1"><span <i class="ri-check-double-line text-muted align-bottom me-1"><span