mirror of
https://git.imnavajas.es/jjimenez/erp-imprimelibros.git
synced 2026-01-13 08:58:48 +00:00
direcciones terminadas
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
package com.imprimelibros.erp.direcciones;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@ -7,10 +8,14 @@ import java.util.Map;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
@ -25,6 +30,7 @@ import com.imprimelibros.erp.datatables.DataTablesRequest;
|
||||
import com.imprimelibros.erp.datatables.DataTablesResponse;
|
||||
import com.imprimelibros.erp.i18n.TranslationService;
|
||||
import com.imprimelibros.erp.paises.PaisesService;
|
||||
import com.imprimelibros.erp.users.User;
|
||||
import com.imprimelibros.erp.users.UserDao;
|
||||
import com.imprimelibros.erp.users.UserDetailsImpl;
|
||||
|
||||
@ -43,6 +49,7 @@ public class DireccionController {
|
||||
protected final UserDao userRepo;
|
||||
protected final TranslationService translationService;
|
||||
|
||||
|
||||
public DireccionController(DireccionRepository repo, PaisesService paisesService,
|
||||
MessageSource messageSource, UserDao userRepo, TranslationService translationService) {
|
||||
this.repo = repo;
|
||||
@ -60,19 +67,25 @@ public class DireccionController {
|
||||
model.addAttribute("isUser", isUser ? 1 : 0);
|
||||
|
||||
List<String> keys = List.of(
|
||||
"margenes-presupuesto.delete.title",
|
||||
"margenes-presupuesto.delete.text",
|
||||
"margenes-presupuesto.eliminar",
|
||||
"margenes-presupuesto.delete.button",
|
||||
"direcciones.delete.title",
|
||||
"direcciones.delete.text",
|
||||
"direcciones.eliminar",
|
||||
"direcciones.delete.button",
|
||||
"app.yes",
|
||||
"app.cancelar",
|
||||
"margenes-presupuesto.delete.ok.title",
|
||||
"margenes-presupuesto.delete.ok.text");
|
||||
"direcciones.delete.ok.title",
|
||||
"direcciones.delete.ok.text",
|
||||
"direcciones.btn.edit",
|
||||
"direcciones.btn.delete",
|
||||
"direcciones.telefono", "direcciones.isFacturacionShort");
|
||||
|
||||
Map<String, String> translations = translationService.getTranslations(locale, keys);
|
||||
model.addAttribute("languageBundle", translations);
|
||||
|
||||
return "imprimelibros/direcciones/direccion-list";
|
||||
if (isUser)
|
||||
return "imprimelibros/direcciones/direccion-list-cliente";
|
||||
else
|
||||
return "imprimelibros/direcciones/direccion-list";
|
||||
}
|
||||
|
||||
@GetMapping(value = "/datatable", produces = "application/json")
|
||||
@ -172,12 +185,83 @@ public class DireccionController {
|
||||
.toJson(total);
|
||||
}
|
||||
|
||||
@GetMapping(value = "/datatableDirecciones", produces = "application/json")
|
||||
@ResponseBody
|
||||
public DataTablesResponse<Map<String, Object>> datatableCliente(
|
||||
HttpServletRequest request,
|
||||
Authentication authentication,
|
||||
Locale locale) {
|
||||
|
||||
DataTablesRequest dt = DataTablesParser.from(request);
|
||||
|
||||
// Columnas visibles / lógicas para el DataTable en el frontend:
|
||||
// id, cliente (nombre de usuario), alias, att, direccion, cp, ciudad,
|
||||
// provincia, pais
|
||||
List<String> searchable = List.of(
|
||||
"id",
|
||||
"alias",
|
||||
"att", "direccion", "cp", "ciudad", "provincia", "pais", "telefono", "is_facturacion", "razonSocial",
|
||||
"identificacionFiscal");
|
||||
|
||||
List<String> orderable = List.of(
|
||||
"id",
|
||||
"cliente", "alias",
|
||||
"att", "direccion", "cp", "ciudad", "provincia", "pais", "telefono");
|
||||
|
||||
// Filtro base por rol (ROLE_USER solo ve sus direcciones)
|
||||
Specification<Direccion> base = (root, query, cb) -> {
|
||||
List<Predicate> predicates = new ArrayList<>();
|
||||
|
||||
if (authentication != null && authentication.getAuthorities().stream()
|
||||
.anyMatch(a -> a.getAuthority().equals("ROLE_USER"))) {
|
||||
String username = authentication.getName();
|
||||
predicates.add(cb.equal(root.get("user").get("userName"), username));
|
||||
}
|
||||
|
||||
return cb.and(predicates.toArray(new Predicate[0]));
|
||||
};
|
||||
|
||||
long total = repo.count(base);
|
||||
|
||||
// Construcción del datatable con entity + spec
|
||||
return DataTable
|
||||
.of(repo, Direccion.class, dt, searchable)
|
||||
.orderable(orderable)
|
||||
|
||||
// Columnas "crudas" (las que existen tal cual):
|
||||
.edit("id", d -> d.getId())
|
||||
.edit("alias", d -> d.getAlias())
|
||||
.edit("att", d -> d.getAtt())
|
||||
.edit("direccion", d -> d.getDireccion())
|
||||
.edit("cp", d -> d.getCp())
|
||||
.edit("ciudad", d -> d.getCiudad())
|
||||
.edit("provincia", d -> d.getProvincia())
|
||||
.edit("telefono", d -> d.getTelefono())
|
||||
.edit("is_facturacion", d -> d.isDireccionFacturacion())
|
||||
.edit("razon_social", d -> d.getRazonSocial())
|
||||
.edit("tipo_identificacion_fiscal", d -> d.getTipoIdentificacionFiscal())
|
||||
.edit("identificacion_fiscal", d -> d.getIdentificacionFiscal())
|
||||
|
||||
// pais = nombre localizado desde MessageSource usando el keyword del país
|
||||
.add("pais", d -> {
|
||||
// si tienes la relación read-only a Pais (d.getPais()) con .getKeyword()
|
||||
String keyword = (d.getPais() != null) ? d.getPais().getKeyword() : null;
|
||||
if (keyword == null || keyword.isBlank())
|
||||
return d.getPaisCode3();
|
||||
return messageSource.getMessage("paises." + keyword, null, keyword, locale);
|
||||
})
|
||||
// WHERE dinámico (spec base)
|
||||
.where(base)
|
||||
.toJson(total);
|
||||
}
|
||||
|
||||
@GetMapping("form")
|
||||
public String getForm(@RequestParam(required = false) Long id,
|
||||
Direccion direccion,
|
||||
BindingResult binding,
|
||||
Model model,
|
||||
HttpServletResponse response,
|
||||
Authentication auth,
|
||||
Locale locale) {
|
||||
|
||||
model.addAttribute("paises", paisesService.getForSelect("", "", locale).get("results"));
|
||||
@ -196,7 +280,16 @@ public class DireccionController {
|
||||
model.addAttribute("action", "/direcciones/" + id);
|
||||
} else {
|
||||
|
||||
model.addAttribute("dirForm", new Direccion());
|
||||
Direccion newDireccion = new Direccion();
|
||||
boolean isUser = auth != null && auth.getAuthorities().stream()
|
||||
.anyMatch(a -> a.getAuthority().equals("ROLE_USER"));
|
||||
if (isUser) {
|
||||
User user = direccion.getUser() != null ? direccion.getUser() : null;
|
||||
if (user != null) {
|
||||
newDireccion.setUser(user);
|
||||
}
|
||||
}
|
||||
model.addAttribute("dirForm", newDireccion);
|
||||
model.addAttribute("action", "/direcciones");
|
||||
}
|
||||
return "imprimelibros/direcciones/direccion-form :: direccionForm";
|
||||
@ -208,8 +301,17 @@ public class DireccionController {
|
||||
BindingResult binding,
|
||||
Model model,
|
||||
HttpServletResponse response,
|
||||
Authentication auth,
|
||||
Locale locale) {
|
||||
|
||||
boolean isUser = auth != null && auth.getAuthorities().stream()
|
||||
.anyMatch(a -> a.getAuthority().equals("ROLE_USER"));
|
||||
|
||||
if (isUser) {
|
||||
User current = userRepo.findByUserNameIgnoreCaseAndEnabledTrueAndDeletedFalse(auth.getName()).orElse(null);
|
||||
direccion.setUser(current); // ignora lo que venga del hidden
|
||||
}
|
||||
|
||||
if (binding.hasErrors()) {
|
||||
response.setStatus(422);
|
||||
model.addAttribute("paises", paisesService.getForSelect("", "", locale).get("results"));
|
||||
@ -268,37 +370,51 @@ public class DireccionController {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* @DeleteMapping("/{id}")
|
||||
*
|
||||
* @Transactional
|
||||
* public ResponseEntity<?> delete(@PathVariable Long id, Authentication auth,
|
||||
* Locale locale) {
|
||||
*
|
||||
* return repo.findById(id).map(u -> {
|
||||
* try {
|
||||
* u.setDeleted(true);
|
||||
* u.setDeletedAt(LocalDateTime.now());
|
||||
*
|
||||
* repo.save(u); // ← NO delete(); guardamos el soft delete con deleted_by
|
||||
* relleno
|
||||
* return ResponseEntity.ok(Map.of("message",
|
||||
* messageSource.getMessage("margenes-presupuesto.exito.eliminado", null,
|
||||
* locale)));
|
||||
* } catch (Exception ex) {
|
||||
* return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
* .body(Map.of("message",
|
||||
* messageSource.getMessage("margenes-presupuesto.error.delete-internal-error",
|
||||
* null,
|
||||
* locale)));
|
||||
* }
|
||||
* }).orElseGet(() -> ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||
* .body(Map.of("message",
|
||||
* messageSource.getMessage("margenes-presupuesto.error.not-found", null,
|
||||
* locale))));
|
||||
* }
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
@Transactional
|
||||
public ResponseEntity<?> delete(@PathVariable Long id, Authentication auth, Locale locale) {
|
||||
|
||||
Direccion direccion = repo.findById(id).orElse(null);
|
||||
if (direccion == null) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||
.body(Map.of("message", messageSource.getMessage("direcciones.error.noEncontrado", null, locale)));
|
||||
}
|
||||
|
||||
boolean isUser = auth != null && auth.getAuthorities().stream()
|
||||
.anyMatch(a -> a.getAuthority().equals("ROLE_USER"));
|
||||
|
||||
Long ownerId = direccion.getUser() != null ? direccion.getUser().getId() : null;
|
||||
Boolean isOwner = this.isOwnerOrAdmin(auth, ownerId);
|
||||
|
||||
if (isUser && !isOwner) {
|
||||
return ResponseEntity.status(HttpStatus.FORBIDDEN)
|
||||
.body(Map.of("message",
|
||||
messageSource.getMessage("direcciones.error.sinPermiso", null, locale)));
|
||||
}
|
||||
|
||||
try {
|
||||
direccion.setDeleted(true);
|
||||
direccion.setDeletedAt(Instant.now());
|
||||
|
||||
if (auth != null && auth.getPrincipal() instanceof UserDetailsImpl udi) {
|
||||
direccion.setDeletedBy(userRepo.getReferenceById(udi.getId()));
|
||||
} else if (auth != null) {
|
||||
userRepo.findByUserNameIgnoreCase(auth.getName()).ifPresent(direccion::setDeletedBy);
|
||||
}
|
||||
repo.saveAndFlush(direccion);
|
||||
|
||||
return ResponseEntity.ok(Map.of("message",
|
||||
messageSource.getMessage("direcciones.exito.eliminado", null, locale)));
|
||||
|
||||
} catch (Exception ex) {
|
||||
// Devuelve SIEMPRE algo en el catch
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body(Map.of("message",
|
||||
messageSource.getMessage("direcciones.error.delete-internal-error", null, locale),
|
||||
"detail",
|
||||
ex.getClass().getSimpleName() + ": " + (ex.getMessage() != null ? ex.getMessage() : "")));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isOwnerOrAdmin(Authentication auth, Long ownerId) {
|
||||
if (auth == null) {
|
||||
|
||||
Reference in New Issue
Block a user