Commit c0779679 by Antonio Rueda

Implementación de repositorios y tests de integración con persistencia

parent e5609ca6
...@@ -38,8 +38,7 @@ ...@@ -38,8 +38,7 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId> <artifactId>spring-boot-starter-validation</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
...@@ -50,19 +49,7 @@ ...@@ -50,19 +49,7 @@
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId> <artifactId>junit-jupiter</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!--
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.el</artifactId>
<version>3.0.3</version>
</dependency>
-->
</dependencies> </dependencies>
<build> <build>
......
...@@ -14,7 +14,7 @@ import org.springframework.context.ApplicationContext; ...@@ -14,7 +14,7 @@ import org.springframework.context.ApplicationContext;
* *
* @author admin * @author admin
*/ */
@SpringBootApplication(scanBasePackages="es.ujaen.dae.ujacoin.servicios") @SpringBootApplication(scanBasePackages={"es.ujaen.dae.ujacoin.servicios", "es.ujaen.dae.ujacoin.repositorios"})
@EntityScan(basePackages="es.ujaen.dae.ujacoin.entidades") @EntityScan(basePackages="es.ujaen.dae.ujacoin.entidades")
public class UjaCoinApp { public class UjaCoinApp {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
......
...@@ -13,6 +13,7 @@ import java.util.ArrayList; ...@@ -13,6 +13,7 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import javax.persistence.CascadeType;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.FetchType; import javax.persistence.FetchType;
import javax.persistence.Id; import javax.persistence.Id;
...@@ -58,7 +59,7 @@ public class Cliente implements Serializable { ...@@ -58,7 +59,7 @@ public class Cliente implements Serializable {
/** Tarjetas asociadas al cliente (no tiene por qué ser el titular */ /** Tarjetas asociadas al cliente (no tiene por qué ser el titular */
@OneToMany(fetch = FetchType.EAGER) @OneToMany(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
@JoinColumn(name="cliente_dni") @JoinColumn(name="cliente_dni")
List<Tarjeta> tarjetas; List<Tarjeta> tarjetas;
......
...@@ -13,6 +13,7 @@ import java.util.ArrayList; ...@@ -13,6 +13,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.persistence.CascadeType;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
...@@ -45,10 +46,13 @@ public class Cuenta { ...@@ -45,10 +46,13 @@ public class Cuenta {
Cliente titular; Cliente titular;
/** Lista de movimientos */ /** Lista de movimientos */
@OneToMany @OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="cuenta_num") @JoinColumn(name="cuenta_num")
List<Movimiento> movimientos; List<Movimiento> movimientos;
public Cuenta() {
}
public Cuenta(String num, Cliente titular) { public Cuenta(String num, Cliente titular) {
this.num = num; this.num = num;
this.titular = titular; this.titular = titular;
...@@ -91,17 +95,21 @@ public class Cuenta { ...@@ -91,17 +95,21 @@ public class Cuenta {
* @return la lista de movimientos dentro del intervalo de fechas indicado * @return la lista de movimientos dentro del intervalo de fechas indicado
*/ */
public List<Movimiento> listarMovimientosDesdeHasta(LocalDateTime fechaHoraDesde, LocalDateTime fechaHoraHasta) { public List<Movimiento> listarMovimientosDesdeHasta(LocalDateTime fechaHoraDesde, LocalDateTime fechaHoraHasta) {
LocalDateTime fechaHoraDesdeConsulta = Optional.ofNullable(fechaHoraHasta).orElseGet( if (fechaHoraDesde == null) {
() -> { LocalDateTime ahora = LocalDateTime.now();
LocalDateTime ahora = LocalDateTime.now(); fechaHoraDesde = ahora.minusDays(ahora.getDayOfMonth() - 1);
return ahora.minusDays(ahora.getDayOfMonth() - 1); }
}
); if (fechaHoraHasta == null) {
LocalDateTime fechaHoraHastaConsulta = Optional.ofNullable(fechaHoraHasta).orElse(LocalDateTime.now()); fechaHoraHasta = LocalDateTime.now();
}
final LocalDateTime desde = fechaHoraDesde;
final LocalDateTime hasta = fechaHoraHasta;
return movimientos.stream().filter(m -> return movimientos.stream().filter(m ->
m.getFechaHora().isAfter(fechaHoraDesdeConsulta) && m.getFechaHora().isAfter(desde) &&
m.getFechaHora().isBefore(fechaHoraHastaConsulta) m.getFechaHora().isBefore(hasta)
).collect(Collectors.toList()); ).collect(Collectors.toList());
} }
......
...@@ -31,7 +31,6 @@ public abstract class Movimiento implements Serializable { ...@@ -31,7 +31,6 @@ public abstract class Movimiento implements Serializable {
@PastOrPresent @PastOrPresent
LocalDateTime fechaHora; LocalDateTime fechaHora;
/** Importe del movimiento. Los valores negativos representan retiradas de dinero */ /** Importe del movimiento. Los valores negativos representan retiradas de dinero */
@Positive
float importe; float importe;
public Movimiento() { public Movimiento() {
......
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package es.ujaen.dae.ujacoin.repositorios;
import es.ujaen.dae.ujacoin.entidades.Cliente;
import es.ujaen.dae.ujacoin.entidades.Tarjeta;
import java.util.Optional;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
/**
*
* @author ajrueda
*/
@Repository
@Transactional
public class RepositorioClientes {
@PersistenceContext
EntityManager em;
public Optional<Cliente> buscar(String dni) {
return Optional.ofNullable(em.find(Cliente.class, dni));
}
public void guardar(Cliente cliente) {
em.persist(cliente);
}
public void nuevaTarjeta(Cliente cliente, Tarjeta tarjeta) {
em.persist(tarjeta);
cliente = em.merge(cliente);
cliente.nuevaTarjeta(tarjeta);
}
public void actualizar(Cliente cliente) {
em.merge(cliente);
}
}
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package es.ujaen.dae.ujacoin.repositorios;
import es.ujaen.dae.ujacoin.entidades.Cuenta;
import java.util.Optional;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
/**
*
* @author ajrueda
*/
@Repository
@Transactional
public class RepositorioCuentas {
@PersistenceContext
EntityManager em;
public Optional<Cuenta> buscar(String num) {
return Optional.ofNullable(em.find(Cuenta.class, num));
}
public void guardar(Cuenta cuenta) {
em.persist(cuenta);
}
}
...@@ -12,22 +12,26 @@ import es.ujaen.dae.ujacoin.entidades.Cliente; ...@@ -12,22 +12,26 @@ import es.ujaen.dae.ujacoin.entidades.Cliente;
import es.ujaen.dae.ujacoin.entidades.Cuenta; import es.ujaen.dae.ujacoin.entidades.Cuenta;
import es.ujaen.dae.ujacoin.entidades.Tarjeta; import es.ujaen.dae.ujacoin.entidades.Tarjeta;
import es.ujaen.dae.ujacoin.entidades.movimientos.Ingreso; import es.ujaen.dae.ujacoin.entidades.movimientos.Ingreso;
import es.ujaen.dae.ujacoin.entidades.movimientos.Movimiento;
import es.ujaen.dae.ujacoin.entidades.movimientos.Reintegro; import es.ujaen.dae.ujacoin.entidades.movimientos.Reintegro;
import es.ujaen.dae.ujacoin.entidades.movimientos.TransferenciaEmitida; import es.ujaen.dae.ujacoin.entidades.movimientos.TransferenciaEmitida;
import es.ujaen.dae.ujacoin.entidades.movimientos.TransferenciaRecibida; import es.ujaen.dae.ujacoin.entidades.movimientos.TransferenciaRecibida;
import es.ujaen.dae.ujacoin.excepciones.ClienteNoRegistrado; import es.ujaen.dae.ujacoin.excepciones.ClienteNoRegistrado;
import es.ujaen.dae.ujacoin.excepciones.ClienteYaRegistrado; import es.ujaen.dae.ujacoin.excepciones.ClienteYaRegistrado;
import es.ujaen.dae.ujacoin.repositorios.RepositorioClientes;
import es.ujaen.dae.ujacoin.repositorios.RepositorioCuentas;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Random;
import java.util.TreeMap;
import javax.validation.Valid; import javax.validation.Valid;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import javax.validation.constraints.Past;
import javax.validation.constraints.Positive; import javax.validation.constraints.Positive;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
/** /**
...@@ -40,13 +44,19 @@ import org.springframework.validation.annotation.Validated; ...@@ -40,13 +44,19 @@ import org.springframework.validation.annotation.Validated;
@Validated @Validated
public class ServicioUjaCoin { public class ServicioUjaCoin {
/** Mapa con la lista de clientes ordenada por DNI */ /** Mapa con la lista de clientes ordenada por DNI */
Map<String, Cliente> clientes; // Map<String, Cliente> clientes;
/** Mapa con la lista de cuentas ordenada por número */ /** Mapa con la lista de cuentas ordenada por número */
Map<String, Cuenta> cuentas; // Map<String, Cuenta> cuentas;
@Autowired
RepositorioClientes repositorioClientes;
@Autowired
RepositorioCuentas repositorioCuentas;
public ServicioUjaCoin() { public ServicioUjaCoin() {
clientes = new TreeMap<>(); // clientes = new TreeMap<>();
cuentas = new TreeMap<>(); // cuentas = new TreeMap<>();
} }
/** /**
...@@ -55,16 +65,25 @@ public class ServicioUjaCoin { ...@@ -55,16 +65,25 @@ public class ServicioUjaCoin {
* @return la cuenta asociada al cliente * @return la cuenta asociada al cliente
*/ */
public Cuenta altaCliente(@NotNull @Valid Cliente cliente) { public Cuenta altaCliente(@NotNull @Valid Cliente cliente) {
/*
if (clientes.containsKey(cliente.getDni())) { if (clientes.containsKey(cliente.getDni())) {
throw new ClienteYaRegistrado(); throw new ClienteYaRegistrado();
} }
// Registrar cliente // Registrar cliente
clientes.put(cliente.getDni(), cliente); clientes.put(cliente.getDni(), cliente);
*/
if (repositorioClientes.buscar(cliente.getDni()).isPresent()) {
throw new ClienteYaRegistrado();
}
repositorioClientes.guardar(cliente);
// Crear y registrar cuenta // Crear y registrar cuenta
Cuenta cuenta = crearCuenta(cliente); Cuenta cuenta = crearCuenta(cliente);
cuentas.put(cuenta.getNum(), cuenta); //cuentas.put(cuenta.getNum(), cuenta);
repositorioCuentas.guardar(cuenta);
return cuenta; return cuenta;
} }
...@@ -75,8 +94,15 @@ public class ServicioUjaCoin { ...@@ -75,8 +94,15 @@ public class ServicioUjaCoin {
* @param clave la clave de acceso * @param clave la clave de acceso
* @return el objeto de la clase Cliente asociado * @return el objeto de la clase Cliente asociado
*/ */
@Transactional
public Optional<Cliente> loginCliente(@NotBlank String dni, @NotBlank String clave) { public Optional<Cliente> loginCliente(@NotBlank String dni, @NotBlank String clave) {
return Optional.ofNullable(clientes.get(dni)).filter((cliente)->cliente.claveValida(clave)); //return Optional.ofNullable(clientes.get(dni)).filter((cliente)->cliente.claveValida(clave));
Optional<Cliente> clienteLogin = repositorioClientes.buscar(dni)
.filter((cliente)->cliente.claveValida(clave));
// Asegurarnos de que se devuelve el cliente con los datos precargados
clienteLogin.ifPresent(c -> c.verCuentas().size());
return clienteLogin;
} }
/** /**
...@@ -85,8 +111,14 @@ public class ServicioUjaCoin { ...@@ -85,8 +111,14 @@ public class ServicioUjaCoin {
* @return la cuenta creada * @return la cuenta creada
*/ */
public Cuenta crearCuenta(@NotBlank String dni) { public Cuenta crearCuenta(@NotBlank String dni) {
Cliente cliente = Optional.ofNullable(clientes.get(dni)).orElseThrow(ClienteNoRegistrado::new); // Cliente cliente = Optional.ofNullable(clientes.get(dni)).orElseThrow(ClienteNoRegistrado::new);
return crearCuenta(cliente); Cliente cliente = repositorioClientes.buscar(dni).orElseThrow(ClienteNoRegistrado::new);
Cuenta cuenta = crearCuenta(cliente);
// cuentas.put(cuenta.getNum(), cuenta);
repositorioCuentas.guardar(cuenta);
return cuenta;
} }
/** /**
...@@ -94,8 +126,10 @@ public class ServicioUjaCoin { ...@@ -94,8 +126,10 @@ public class ServicioUjaCoin {
* @param dni el DNI del cliente * @param dni el DNI del cliente
* @param tarjeta la tarjeta a registrar * @param tarjeta la tarjeta a registrar
*/ */
@Transactional
public void registrarTarjeta(@NotBlank String dni, @NotNull @Valid Tarjeta tarjeta) { public void registrarTarjeta(@NotBlank String dni, @NotNull @Valid Tarjeta tarjeta) {
Cliente cliente = Optional.ofNullable(clientes.get(dni)).orElseThrow(ClienteNoRegistrado::new); // Cliente cliente = Optional.ofNullable(clientes.get(dni)).orElseThrow(ClienteNoRegistrado::new);
Cliente cliente = repositorioClientes.buscar(dni).orElseThrow(ClienteNoRegistrado::new);
cliente.verTarjeta(tarjeta.getNum()).ifPresent(x -> { throw new TarjetaYaRegistrada(); } ); cliente.verTarjeta(tarjeta.getNum()).ifPresent(x -> { throw new TarjetaYaRegistrada(); } );
cliente.nuevaTarjeta(tarjeta); cliente.nuevaTarjeta(tarjeta);
...@@ -103,22 +137,32 @@ public class ServicioUjaCoin { ...@@ -103,22 +137,32 @@ public class ServicioUjaCoin {
/** /**
* Devolver las cuentas de un cliente dado * Devolver las cuentas de un cliente dado
* No es una operación imprescindible puesto que el cliente ya
* tiene la lista de cuentas
* @param dni el DNI del cliente * @param dni el DNI del cliente
* @return la lista de cuentas * @return la lista de cuentas
*/ */
@Transactional
public List<Cuenta> verCuentas(@NotBlank String dni) { public List<Cuenta> verCuentas(@NotBlank String dni) {
Cliente cliente = Optional.ofNullable(clientes.get(dni)).orElseThrow(ClienteNoRegistrado::new); //Cliente cliente = Optional.ofNullable(clientes.get(dni)).orElseThrow(ClienteNoRegistrado::new);
Cliente cliente = repositorioClientes.buscar(dni).orElseThrow(ClienteNoRegistrado::new);
// Precargar a memoria la relación lazy de cuentas del cliente antes de devolver
cliente.verCuentas().size();
return cliente.verCuentas(); return cliente.verCuentas();
} }
/** /**
* Devolver las tarjetas registradas por el usuario * Devolver las tarjetas registradas por el usuario. No es una operación
* realmente necesaria puesto que el cliente ya contiene esta lista
* @param dni el DNI del cliente * @param dni el DNI del cliente
* @return la lista de tarjetas * @return la lista de tarjetas
*/ */
public List<Tarjeta> verTarjetas(@NotBlank String dni) { public List<Tarjeta> verTarjetas(@NotBlank String dni) {
Cliente cliente = Optional.ofNullable(clientes.get(dni)).orElseThrow(ClienteNoRegistrado::new); // Cliente cliente = Optional.ofNullable(clientes.get(dni)).orElseThrow(ClienteNoRegistrado::new);
return cliente.verTarjetas();
Cliente cliente = repositorioClientes.buscar(dni).orElseThrow(ClienteNoRegistrado::new);
return cliente.verTarjetas(); // Relación eager, no hay que hacer nada
} }
/** /**
...@@ -127,13 +171,17 @@ public class ServicioUjaCoin { ...@@ -127,13 +171,17 @@ public class ServicioUjaCoin {
* @param numTarjeta el número de la tarjeta desde donde se retira el dinero * @param numTarjeta el número de la tarjeta desde donde se retira el dinero
* @param importe el importe a ingresar en euros (se tiene en cuenta el cambio euro-UJACoin actual) * @param importe el importe a ingresar en euros (se tiene en cuenta el cambio euro-UJACoin actual)
*/ */
@Transactional
public void ingreso(@NotBlank String numCuenta, @NotBlank String numTarjeta, @Positive float importe) { public void ingreso(@NotBlank String numCuenta, @NotBlank String numTarjeta, @Positive float importe) {
Cuenta cuenta = Optional.ofNullable(cuentas.get(numCuenta)) // Cuenta cuenta = Optional.ofNullable(cuentas.get(numCuenta))
// .orElseThrow(CuentaNoRegistrada::new);
Cuenta cuenta = repositorioCuentas.buscar(numCuenta)
.orElseThrow(CuentaNoRegistrada::new); .orElseThrow(CuentaNoRegistrada::new);
Tarjeta tarjeta = cuenta.getTitular().verTarjeta(numTarjeta) Tarjeta tarjeta = cuenta.getTitular().verTarjeta(numTarjeta)
.orElseThrow(TarjetaNoRegistrada::new); .orElseThrow(TarjetaNoRegistrada::new);
cuenta.nuevoMovimiento(new Ingreso(tarjeta, importe)); cuenta.nuevoMovimiento(new Ingreso(tarjeta, importe));
} }
...@@ -143,8 +191,12 @@ public class ServicioUjaCoin { ...@@ -143,8 +191,12 @@ public class ServicioUjaCoin {
* @param numTarjeta el número de la tarjeta donde se hace el ingreso * @param numTarjeta el número de la tarjeta donde se hace el ingreso
* @param importe el importe a retirar * @param importe el importe a retirar
*/ */
@Transactional
public void reintegro(@NotBlank String numCuenta, @NotBlank String numTarjeta, @Positive float importe) { public void reintegro(@NotBlank String numCuenta, @NotBlank String numTarjeta, @Positive float importe) {
Cuenta cuenta = Optional.ofNullable(cuentas.get(numCuenta)) //Cuenta cuenta = Optional.ofNullable(cuentas.get(numCuenta))
// .orElseThrow(CuentaNoRegistrada::new);
Cuenta cuenta = repositorioCuentas.buscar(numCuenta)
.orElseThrow(CuentaNoRegistrada::new); .orElseThrow(CuentaNoRegistrada::new);
Tarjeta tarjeta = cuenta.getTitular().verTarjeta(numTarjeta) Tarjeta tarjeta = cuenta.getTitular().verTarjeta(numTarjeta)
...@@ -159,27 +211,67 @@ public class ServicioUjaCoin { ...@@ -159,27 +211,67 @@ public class ServicioUjaCoin {
* @param numCuentaDestino el número de la cuenta destino * @param numCuentaDestino el número de la cuenta destino
* @param importe el importe a transferir * @param importe el importe a transferir
*/ */
@Transactional
public void transferencia(@NotBlank String numCuentaOrigen, @NotBlank String numCuentaDestino, @Positive float importe) { public void transferencia(@NotBlank String numCuentaOrigen, @NotBlank String numCuentaDestino, @Positive float importe) {
Cuenta cuentaOrigen = Optional.ofNullable(cuentas.get(numCuentaOrigen)) // Cuenta cuentaOrigen = Optional.ofNullable(cuentas.get(numCuentaOrigen))
.orElseThrow(CuentaNoRegistrada::new); // .orElseThrow(CuentaNoRegistrada::new);
Cuenta cuentaDestino = Optional.ofNullable(cuentas.get(numCuentaDestino)) Cuenta cuentaOrigen = repositorioCuentas.buscar(numCuentaOrigen)
.orElseThrow(CuentaNoRegistrada::new); .orElseThrow(CuentaNoRegistrada::new);
// Cuenta cuentaDestino = Optional.ofNullable(cuentas.get(numCuentaDestino))
// .orElseThrow(CuentaNoRegistrada::new);
Cuenta cuentaDestino = repositorioCuentas.buscar(numCuentaDestino)
.orElseThrow(CuentaNoRegistrada::new);
cuentaOrigen.nuevoMovimiento(new TransferenciaEmitida(cuentaDestino, importe)); cuentaOrigen.nuevoMovimiento(new TransferenciaEmitida(cuentaDestino, importe));
cuentaDestino.nuevoMovimiento(new TransferenciaRecibida(cuentaOrigen, importe)); cuentaDestino.nuevoMovimiento(new TransferenciaRecibida(cuentaOrigen, importe));
} }
/**
* Devolver la lista de movimientos de la cuenta, filtrada por fechas
* @param numCuenta el número de la cuenta
* @param fechaHoraDesde la fecha inicial
* @param fechaHoraHasta la fecha final
* @return la lista de los movimientos entre las fechas indicadas
*/
@Transactional
List<Movimiento> listarMovimientosCuentaDesdeHasta(@NotBlank String numCuenta, @Past LocalDateTime fechaHoraDesde, @Past LocalDateTime fechaHoraHasta) {
Cuenta cuenta = repositorioCuentas.buscar(numCuenta)
.orElseThrow(CuentaNoRegistrada::new);
return cuenta.listarMovimientosDesdeHasta(fechaHoraDesde, fechaHoraHasta);
}
/**
* Listar movimientos desde una fecha dada
* @param numCuenta el número de la cuenta
* @param fechaHoraDesde fecha de primer movimiento
* @return el listado de movimientos
*/
@Transactional
public List<Movimiento> listarMovimientosDesde(@NotBlank String numCuenta, @Past LocalDateTime fechaHoraDesde) {
Cuenta cuenta = repositorioCuentas.buscar(numCuenta)
.orElseThrow(CuentaNoRegistrada::new);
return cuenta.listarMovimientosDesde(fechaHoraDesde);
}
// Crear una cuenta para el cliente indicado con un número no asignado // Crear una cuenta para el cliente indicado con un número no asignado
private Cuenta crearCuenta(Cliente cliente) { private Cuenta crearCuenta(Cliente cliente) {
// Generar número de cuenta de 10 dígitos aleatorio y no usado previamente // Generar número de cuenta de 10 dígitos aleatorio y no usado previamente
String numCuenta; String numCuenta;
long min = 1000000000L;
long max = 8999999999L;
do { do {
numCuenta = Long.toString((new Random().nextLong() % 9000000000L) + 1000000000L); numCuenta = Long.toString(min + (long) (Math.random() * (max - min)));
} while (cuentas.containsKey(numCuenta)); } while (repositorioCuentas.buscar(numCuenta).isPresent());
Cuenta cuenta = new Cuenta(numCuenta, cliente); Cuenta cuenta = new Cuenta(numCuenta, cliente);
cliente.nuevaCuenta(cuenta);
// No es necesario al ser una relación bidireccional gestionada por JPA
// cliente.nuevaCuenta(cuenta);
return cuenta; return cuenta;
} }
......
...@@ -4,7 +4,7 @@ spring.datasource.url: jdbc:mysql://localhost:33060/ujacoin ...@@ -4,7 +4,7 @@ spring.datasource.url: jdbc:mysql://localhost:33060/ujacoin
spring.datasource.username: ujacoin spring.datasource.username: ujacoin
spring.datasource.password: secret spring.datasource.password: secret
spring.jpa.properties.javax.persistence.schema-generation.database.action: drop-and-create spring.jpa.properties.javax.persistence.schema-generation.database.action: none
spring.data.jpa.repositories.bootstrap-mode: default spring.data.jpa.repositories.bootstrap-mode: default
......
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package es.ujaen.dae.ujacoin.servicios;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
/**
* Servicio auxiliar de borrado de los datos en la base de datos (sólo para testing)
* @author ajrueda
*/
@Service
public class ServicioLimpiadoBaseDatos {
@PersistenceContext
EntityManager em;
@Autowired
TransactionTemplate transactionTemplate;
/**
* Lista de entidades a borrar. Ojo: el orden es muy importante
* para evitar errores de violación de integridad
*/
final String[] entidades = {
"Movimiento",
"Cuenta",
"Tarjeta",
"Cliente"
};
final String deleteFrom = "delete from ";
/** Realizar borrado */
void limpiar() {
transactionTemplate.executeWithoutResult(transactionStatus -> {
for (String tabla : entidades) {
em.createQuery(deleteFrom + tabla).executeUpdate();
}
});
}
}
...@@ -9,37 +9,40 @@ import es.ujaen.dae.ujacoin.entidades.Cliente; ...@@ -9,37 +9,40 @@ import es.ujaen.dae.ujacoin.entidades.Cliente;
import es.ujaen.dae.ujacoin.entidades.Cuenta; import es.ujaen.dae.ujacoin.entidades.Cuenta;
import es.ujaen.dae.ujacoin.entidades.Tarjeta; import es.ujaen.dae.ujacoin.entidades.Tarjeta;
import es.ujaen.dae.ujacoin.entidades.movimientos.Ingreso; import es.ujaen.dae.ujacoin.entidades.movimientos.Ingreso;
import es.ujaen.dae.ujacoin.entidades.movimientos.Movimiento;
import es.ujaen.dae.ujacoin.entidades.movimientos.TransferenciaEmitida; import es.ujaen.dae.ujacoin.entidades.movimientos.TransferenciaEmitida;
import es.ujaen.dae.ujacoin.entidades.movimientos.TransferenciaRecibida; import es.ujaen.dae.ujacoin.entidades.movimientos.TransferenciaRecibida;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import javax.validation.ConstraintViolationException; import javax.validation.ConstraintViolationException;
import org.assertj.core.api.Assertions; import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.MethodMode;
/** /**
* *
* @author ajrueda * @author ajrueda
*/ */
//@Disabled // @Disabled
@SpringBootTest(classes = es.ujaen.dae.ujacoin.app.UjaCoinApp.class) @SpringBootTest(classes = es.ujaen.dae.ujacoin.app.UjaCoinApp.class)
public class ServicioUjaCoinTest { public class ServicioUjaCoinTest {
@Autowired @Autowired
ServicioUjaCoin servicioUjaCoin; ServicioUjaCoin servicioUjaCoin;
@Autowired
ServicioLimpiadoBaseDatos limpiadorBaseDatos;
@Test @Test
public void testAccesoServicioUjaCoin() { public void testAccesoServicioUjaCoin() {
Assertions.assertThat(servicioUjaCoin).isNotNull(); Assertions.assertThat(servicioUjaCoin).isNotNull();
} }
@Test @Test
@DirtiesContext(methodMode = MethodMode.AFTER_METHOD)
public void testAltaClienteInvalido() { public void testAltaClienteInvalido() {
// Cliente con e-mail incorrecto!!! // Cliente con e-mail incorrecto!!!
Cliente cliente = new Cliente( Cliente cliente = new Cliente(
...@@ -57,7 +60,6 @@ public class ServicioUjaCoinTest { ...@@ -57,7 +60,6 @@ public class ServicioUjaCoinTest {
} }
@Test @Test
@DirtiesContext(methodMode = MethodMode.AFTER_METHOD)
public void testAltaYLoginClienteCuenta() { public void testAltaYLoginClienteCuenta() {
Cliente cliente = new Cliente( Cliente cliente = new Cliente(
"11995667D", "11995667D",
...@@ -68,15 +70,60 @@ public class ServicioUjaCoinTest { ...@@ -68,15 +70,60 @@ public class ServicioUjaCoinTest {
"jee@gmail.com", "jee@gmail.com",
"clave"); "clave");
Cuenta cuenta = servicioUjaCoin.altaCliente(cliente); servicioUjaCoin.altaCliente(cliente);
Optional<Cliente> clienteLogin = servicioUjaCoin.loginCliente(cliente.getDni(), "clave"); Optional<Cliente> clienteLogin = servicioUjaCoin.loginCliente(cliente.getDni(), "clave");
Assertions.assertThat(clienteLogin.isPresent()).isTrue(); Assertions.assertThat(clienteLogin.isPresent()).isTrue();
Assertions.assertThat(clienteLogin.get()).isEqualTo(cliente); Assertions.assertThat(clienteLogin.get().getDni()).isEqualTo(cliente.getDni());
Assertions.assertThat(clienteLogin.get().verCuentas()).isNotEmpty();
}
@Test
public void testCreacionCuentaAdicional() {
Cliente cliente = new Cliente(
"11995667D",
"Juan España España",
LocalDate.of(1990, 11, 1),
"Cl La Luz, 13 - Jaén",
"988674533",
"jee@gmail.com",
"clave");
servicioUjaCoin.altaCliente(cliente);
// Crear cuenta adicional
servicioUjaCoin.crearCuenta(cliente.getDni());
Optional<Cliente> clienteLogin = servicioUjaCoin.loginCliente(cliente.getDni(), "clave");
Assertions.assertThat(clienteLogin.get().verCuentas()).hasSize(2);
Assertions.assertThat(clienteLogin.get().verCuentas().get(0).getNum())
.isNotEqualTo(clienteLogin.get().verCuentas().get(1).getNum());
} }
@Test @Test
@DirtiesContext(methodMode = MethodMode.AFTER_METHOD) public void testAnadirTarjetaACliente() {
// Registrar cliente y realizar login
Cliente cliente = new Cliente(
"11995667D",
"Juan España España",
LocalDate.of(1990, 11, 1),
"Cl La Luz, 13 - Jaén",
"988674533",
"jee@gmail.com",
"clave");
// Crear cliente
servicioUjaCoin.altaCliente(cliente);
// Añadir una tarjeta
Tarjeta tarjeta = new Tarjeta("4111111111111111", cliente.getNombre(), LocalDate.of(2022, 12, 1), "365");
servicioUjaCoin.registrarTarjeta(cliente.getDni(), tarjeta);
Cliente clienteLogin = servicioUjaCoin.loginCliente(cliente.getDni(), "clave").get();
Assertions.assertThat(clienteLogin.verTarjeta(tarjeta.getNum())).isNotEmpty();
}
@Test
public void testIngreso() { public void testIngreso() {
// Registrar cliente y realizar login // Registrar cliente y realizar login
Cliente cliente = new Cliente( Cliente cliente = new Cliente(
...@@ -102,13 +149,14 @@ public class ServicioUjaCoinTest { ...@@ -102,13 +149,14 @@ public class ServicioUjaCoinTest {
// Realizar ingreso y comprobar estado de la cuenta // Realizar ingreso y comprobar estado de la cuenta
servicioUjaCoin.ingreso(cuentas.get(0).getNum(), tarjeta.getNum(), 1000); servicioUjaCoin.ingreso(cuentas.get(0).getNum(), tarjeta.getNum(), 1000);
Assertions.assertThat(cuentas.get(0).listarMovimientos()).hasSize(1);
Assertions.assertThat(cuentas.get(0).listarMovimientos().get(0)).isInstanceOf(Ingreso.class); List<Movimiento> movimientos = servicioUjaCoin.listarMovimientosDesde(cuentas.get(0).getNum(), LocalDateTime.MIN);
Assertions.assertThat(cuentas.get(0).getSaldo()).isEqualTo(1000); Assertions.assertThat(movimientos).hasSize(1);
Assertions.assertThat(movimientos.get(0)).isInstanceOf(Ingreso.class);
Assertions.assertThat(movimientos.get(0).getImporte()).isEqualTo(1000);
} }
@Test @Test
@DirtiesContext(methodMode = MethodMode.AFTER_METHOD)
public void testTransferencia() { public void testTransferencia() {
// Registrar cliente // Registrar cliente
Cliente cliente = new Cliente( Cliente cliente = new Cliente(
...@@ -120,7 +168,7 @@ public class ServicioUjaCoinTest { ...@@ -120,7 +168,7 @@ public class ServicioUjaCoinTest {
"jee@gmail.com", "jee@gmail.com",
"claveyyy"); "claveyyy");
Cuenta cuenta = servicioUjaCoin.altaCliente(cliente); Cuenta cuentaOrigen = servicioUjaCoin.altaCliente(cliente);
// Añadir una tarjeta // Añadir una tarjeta
Tarjeta tarjeta = new Tarjeta("4111111111111111", cliente.getNombre(), LocalDate.of(2022, 12, 1), "365"); Tarjeta tarjeta = new Tarjeta("4111111111111111", cliente.getNombre(), LocalDate.of(2022, 12, 1), "365");
...@@ -128,7 +176,6 @@ public class ServicioUjaCoinTest { ...@@ -128,7 +176,6 @@ public class ServicioUjaCoinTest {
cliente.nuevaTarjeta(tarjeta); cliente.nuevaTarjeta(tarjeta);
// Obtener cuenta y realizar ingreso en cuenta // Obtener cuenta y realizar ingreso en cuenta
Cuenta cuentaOrigen = servicioUjaCoin.verCuentas(cliente.getDni()).get(0);
servicioUjaCoin.ingreso(cuentaOrigen.getNum(), tarjeta.getNum(), 1000); servicioUjaCoin.ingreso(cuentaOrigen.getNum(), tarjeta.getNum(), 1000);
// Crear segundo cliente // Crear segundo cliente
...@@ -146,12 +193,26 @@ public class ServicioUjaCoinTest { ...@@ -146,12 +193,26 @@ public class ServicioUjaCoinTest {
// Realizar transferencia y comprobar movimientos // Realizar transferencia y comprobar movimientos
servicioUjaCoin.transferencia(cuentaOrigen.getNum(), cuentaDestino.getNum(), 500); servicioUjaCoin.transferencia(cuentaOrigen.getNum(), cuentaDestino.getNum(), 500);
Assertions.assertThat(cuentaOrigen.listarMovimientos()).hasSize(2);
Assertions.assertThat(cuentaOrigen.listarMovimientos().get(1)).isInstanceOf(TransferenciaEmitida.class); // Refrescar cuenta origen y destino
cuentaOrigen = servicioUjaCoin.verCuentas(cliente.getDni()).get(0);
cuentaDestino = servicioUjaCoin.verCuentas(cliente2.getDni()).get(0);
// Listar movimientos de la cuenta origen
List<Movimiento> movimientos = servicioUjaCoin.listarMovimientosDesde(cuentaOrigen.getNum(), LocalDateTime.MIN);
Assertions.assertThat(movimientos).hasSize(2);
Assertions.assertThat(movimientos.get(1)).isInstanceOf(TransferenciaEmitida.class);
Assertions.assertThat(cuentaOrigen.getSaldo()).isEqualTo(500); Assertions.assertThat(cuentaOrigen.getSaldo()).isEqualTo(500);
Assertions.assertThat(cuentaDestino.listarMovimientos()).hasSize(1); // Listar movimientos de la cuenta destino
Assertions.assertThat(cuentaDestino.listarMovimientos().get(0)).isInstanceOf(TransferenciaRecibida.class); movimientos = servicioUjaCoin.listarMovimientosDesde(cuentaDestino.getNum(), LocalDateTime.MIN);
Assertions.assertThat(movimientos).hasSize(1);
Assertions.assertThat(movimientos.get(0)).isInstanceOf(TransferenciaRecibida.class);
Assertions.assertThat(cuentaDestino.getSaldo()).isEqualTo(500); Assertions.assertThat(cuentaDestino.getSaldo()).isEqualTo(500);
} }
@BeforeEach
void limpiarBaseDatos() {
limpiadorBaseDatos.limpiar();
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment