Commit 62b31fbe by Antonio Rueda

Versión inicial

parents
Showing with 1229 additions and 0 deletions
.DS_Store
target/
<?xml version="1.0" encoding="UTF-8"?>
<actions>
<action>
<actionName>CUSTOM-spring-boot:run</actionName>
<displayName>spring-boot:run</displayName>
<goals>
<goal>spring-boot:run</goal>
</goals>
</action>
</actions>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>es.ujaen.dae</groupId>
<artifactId>UjaCoin</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
/*
* 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.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
/**
*
* @author admin
*/
@SpringBootApplication(scanBasePackages="es.ujaen.dae.ujacoin.servicios")
public class UjaCoinApp {
public static void main(String[] args) throws Exception {
// Creación de servidor
SpringApplication servidor = new SpringApplication(UjaCoinApp.class);
ApplicationContext context = servidor.run(args);
}
}
/*
* 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.entidades;
import es.ujaen.dae.ujacoin.util.ExprReg;
import es.ujaen.dae.ujacoin.util.CodificadorMd5;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Past;
import javax.validation.constraints.Pattern;
/**
* Cliente del banco virtual UjaCoin
* @author ajrueda
*/
public class Cliente {
/** DNI del cliente*/
@Pattern(regexp=ExprReg.DNI)
String dni;
/** Nombre completo */
@NotBlank
String nombre;
/** Fecha de nacimiento */
@Past
LocalDate fNacimiento;
/** Dirección del domicilio */
@NotBlank
String direccion;
/** Teléfono */
@Pattern(regexp=ExprReg.TLF)
String tlf;
/** Email */
@Email
String email;
/** Clave de acceso al sistema */
String clave;
/** Tarjetas asociadas al cliente (no tiene por qué ser el titular */
List<Tarjeta> tarjetas;
/** Cuentas asociadas al cliente */
List<Cuenta> cuentas;
public Cliente(String dni, String nombre, LocalDate fNacimiento, String direccion, String tlf, String email, String clave) {
this.dni = dni;
this.nombre = nombre;
this.fNacimiento = fNacimiento;
this.direccion = direccion;
this.tlf = tlf;
this.email = email;
this.clave = CodificadorMd5.codificar(clave);
tarjetas = new ArrayList<>();
cuentas = new ArrayList<>();
}
public String getDni() {
return dni;
}
public String getNombre() {
return nombre;
}
public LocalDate getfNacimiento() {
return fNacimiento;
}
public String getDireccion() {
return direccion;
}
public String getTlf() {
return tlf;
}
public String getEmail() {
return email;
}
/**
* Compara la clave con la del cliente, codificándola en Md5
* @param clave
* @return
*/
public boolean claveValida(String clave) {
return this.clave.equals(CodificadorMd5.codificar(clave));
}
/**
* Definir nueva tarjeta para operar
* @param tarjeta la nueva tarjeta
*/
public void nuevaTarjeta(Tarjeta tarjeta) {
tarjetas.add(tarjeta);
}
/**
* Asociar una cuenta al usuario
* @param cuenta la cuenta a asociar
*/
public void nuevaCuenta(Cuenta cuenta) {
cuentas.add(cuenta);
}
/**
* Devolver la lista de tarjetas asociadas al usuario
* @return la lista de tarjetas
*/
public List<Tarjeta> verTarjetas() {
return Collections.unmodifiableList(tarjetas);
}
/**
* Busca una tarjeta por número
* @param numTarjeta el número de la tarjeta solicitada
* @return la tarjeta asociada al número indicado
*/
public Optional<Tarjeta> verTarjeta(String numTarjeta) {
return tarjetas.stream()
.filter(t -> t.getNum().equals(numTarjeta))
.findFirst();
}
/**
* Devolver cuentas del usuario
* @return la lista de cuentas
*/
public List<Cuenta> verCuentas() {
return Collections.unmodifiableList(cuentas);
}
/**
* Busca una cuenta por número
* @param numCuenta el número de la cuenta
* @return la cuenta solicitada
*/
public Optional<Cuenta> verCuenta(String numCuenta) {
return cuentas.stream()
.filter(t -> t.getNum().equals(numCuenta))
.findFirst();
}
}
/*
* 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.entidades;
import es.ujaen.dae.ujacoin.excepciones.SaldoInsuficienteParaOperacion;
import es.ujaen.dae.ujacoin.entidades.movimientos.Movimiento;
import es.ujaen.dae.ujacoin.entidades.movimientos.TransferenciaEmitida;
import es.ujaen.dae.ujacoin.util.ExprReg;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.PositiveOrZero;
/**
* Clase para representar cuentas de moneda virtual UjaCoin
* @author ajrueda
*/
public class Cuenta {
/** Número de cuenta */
@Pattern(regexp=ExprReg.NUM_CUENTA)
String num;
/** Saldo de la cuenta en Ujacoins */
@PositiveOrZero
float saldo;
/** Titular de la cuenta */
@NotNull
Cliente titular;
/** Lista de movimientos */
List<Movimiento> movimientos;
public Cuenta(String num, Cliente titular) {
this.num = num;
this.titular = titular;
saldo = 0;
movimientos = new ArrayList<>();
}
public String getNum() {
return num;
}
public float getSaldo() {
return saldo;
}
public Cliente getTitular() {
return titular;
}
/**
* Añadir nuevo movimiento a la cuenta
*
* @param movimiento el nuevo movimiento a registrar: ingreso, reintegro,
* transferencia emitida o recibida
*/
public void nuevoMovimiento(Movimiento movimiento) {
if (saldo + movimiento.getImporte() < 0) {
throw new SaldoInsuficienteParaOperacion();
}
movimiento.setFechaHora(LocalDateTime.now());
movimientos.add(movimiento);
saldo += movimiento.getImporte();
}
/**
* Listar movimientos de la cuenta
* @param fechaHoraDesde fecha y hora inicial para el listado
* @param fechaHoraHasta fecha y hora final para el listado
* @return la lista de movimientos dentro del intervalo de fechas indicado
*/
public List<Movimiento> listarMovimientosDesdeHasta(LocalDateTime fechaHoraDesde, LocalDateTime fechaHoraHasta) {
LocalDateTime fechaHoraDesdeConsulta = Optional.ofNullable(fechaHoraHasta).orElseGet(
() -> {
LocalDateTime ahora = LocalDateTime.now();
return ahora.minusDays(ahora.getDayOfMonth() - 1);
}
);
LocalDateTime fechaHoraHastaConsulta = Optional.ofNullable(fechaHoraHasta).orElse(LocalDateTime.now());
return movimientos.stream().filter(m ->
m.getFechaHora().isAfter(fechaHoraDesdeConsulta) &&
m.getFechaHora().isBefore(fechaHoraHastaConsulta)
).collect(Collectors.toList());
}
/**
* Listar movimientos desde una fecha dada
* @param fechaHoraDesde fecha de primer movimiento
* @return el listado de movimientos
*/
public List<Movimiento> listarMovimientosDesde(LocalDateTime fechaHoraDesde) {
return listarMovimientosDesdeHasta(fechaHoraDesde, null);
}
/**
* Listar movimientos hasta una fecha dada
* @param fechaHoraHasta fecha de último movimiento
* @return el listado de movimientos
*/
public List<Movimiento> listarMovimientosHasta(LocalDateTime fechaHoraHasta) {
return listarMovimientosDesdeHasta(null, fechaHoraHasta);
}
/**
* Listar todos los movimientos
* @return la lista de movimientos
*/
public List<Movimiento> listarMovimientos() {
return listarMovimientosDesdeHasta(null, null);
}
}
/*
* 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.entidades;
import es.ujaen.dae.ujacoin.util.ExprReg;
import java.time.LocalDate;
import javax.validation.constraints.Future;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
/**
* Tarjeta para la realización de ingresos o reintegros en moneda real
* @author ajrueda
*/
public class Tarjeta {
/** Número de tarjeta */
@Pattern(regexp=ExprReg.NUM_TARJETA)
String num;
/** Titular de la tarjeta (puede ser diferente al cliente que la usa */
@NotBlank
String titular;
/** Fecha de caducidad */
@Future
LocalDate fechaCaducidad;
/** Código de seguridad (CVC) */
@Pattern(regexp=ExprReg.CVC)
String cvc;
public Tarjeta(String num, String titular, LocalDate fechaCaducidad, String cvc) {
this.num = num;
this.titular = titular;
this.fechaCaducidad = fechaCaducidad;
this.cvc = cvc;
}
public String getNum() {
return num;
}
public String getTitular() {
return titular;
}
public LocalDate getFechaCaducidad() {
return fechaCaducidad;
}
public String getCvc() {
return cvc;
}
}
/*
* 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.entidades.movimientos;
import es.ujaen.dae.ujacoin.entidades.Tarjeta;
import javax.validation.constraints.NotNull;
/**
* Ingreso de dinero en cuenta desde una tarjeta
* @author ajrueda
*/
public class Ingreso extends Movimiento {
@NotNull
Tarjeta tarjeta;
/**
* Constructor del igreso
* @param tarjeta la tarjeta desde donde se transfiere el dinero
* @param importe el importe a ingresar en cuenta
*/
public Ingreso(Tarjeta tarjeta, float importe) {
super(importe);
this.tarjeta = tarjeta;
}
/**
* Devolver la tarjeta asociada al ingreso
* @return la tarjeta
*/
public Tarjeta getTarjeta() {
return tarjeta;
}
}
/*
* 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.entidades.movimientos;
import java.time.LocalDateTime;
import javax.validation.constraints.PastOrPresent;
import javax.validation.constraints.Positive;
/**
* Clase que representa un movimiento en cuenta
* @author ajrueda
*/
public abstract class Movimiento {
/** Fecha del movimiento */
@PastOrPresent
LocalDateTime fechaHora;
/** Importe del movimiento. Los valores negativos representan retiradas de dinero */
@Positive
float importe;
/**
* Constructor del movimiento
* @param importe el importe asociado al movimiento
*/
public Movimiento(float importe) {
this.importe = importe;
this.fechaHora = LocalDateTime.now();
}
public void setFechaHora(LocalDateTime fechaHora) {
this.fechaHora = fechaHora;
}
public LocalDateTime getFechaHora() {
return fechaHora;
}
public float getImporte() {
return importe;
}
}
/*
* 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.entidades.movimientos;
import es.ujaen.dae.ujacoin.entidades.Tarjeta;
import javax.validation.constraints.NotNull;
/**
* Reintegro desde la cuenta a una tarjeta destino
* @author ajrueda
*/
public class Reintegro extends Movimiento {
@NotNull
Tarjeta tarjeta;
/**
* Constructor del reintegro
* @param tarjeta la tarjeta destino del reintegro
* @param importe el importe a retirar
*/
public Reintegro(Tarjeta tarjeta, float importe) {
super(-importe);
this.tarjeta = tarjeta;
}
/**
* Devolver la tarjeta del reintegro
* @return la tarjeta
*/
public Tarjeta getTarjeta() {
return tarjeta;
}
}
/*
* 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.entidades.movimientos;
import es.ujaen.dae.ujacoin.entidades.Cuenta;
import javax.validation.constraints.NotNull;
/**
* Transferencia emitida a otra cuenta
* @author ajrueda
*/
public class TransferenciaEmitida extends Movimiento {
@NotNull
Cuenta cuenta;
public TransferenciaEmitida(Cuenta cuenta, float importe) {
super(-importe);
this.cuenta = cuenta;
}
public Cuenta getCuentaDestino() {
return cuenta;
}
}
/*
* 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.entidades.movimientos;
import es.ujaen.dae.ujacoin.entidades.Cuenta;
import javax.validation.constraints.NotNull;
/**
* Transferencia recibida de otra cuenta
* @author ajrueda
*/
public class TransferenciaRecibida extends Movimiento {
@NotNull
Cuenta cuenta;
public TransferenciaRecibida(Cuenta cuenta, float importe) {
super(importe);
this.cuenta = cuenta;
}
public Cuenta getCuentaOrigen() {
return cuenta;
}
}
/*
* 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.excepciones;
/**
* Excepción provocada por intentos de acceso o creación de cuentas
* de clientes no registrados
* @author ajrueda
*/
public class ClienteNoRegistrado extends RuntimeException {
public ClienteNoRegistrado() {
}
}
/*
* 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.excepciones;
/**
* Excepcion producida por intento de registro de clientes ya existentes
* @author ajrueda
*/
public class ClienteYaRegistrado extends RuntimeException {
public ClienteYaRegistrado() {
}
}
/*
* 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.excepciones;
/**
* Excepción provocada por cuentas no registradas en el sistema
* @author ajrueda
*/
public class CuentaNoRegistrada extends RuntimeException {
public CuentaNoRegistrada() {
}
}
/*
* 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.excepciones;
/**
* Saldo insuficiente para emitir una transferencia o realizar un reintegro en tarjeta
* @author ajrueda
*/
public class SaldoInsuficienteParaOperacion extends RuntimeException {
public SaldoInsuficienteParaOperacion() {
}
}
/*
* 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.excepciones;
/**
* Excepción asociada a una tarjeta no registrada en el sistema
* @author ajrueda
*/
public class TarjetaNoRegistrada extends RuntimeException {
public TarjetaNoRegistrada() {
}
}
/*
* 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.excepciones;
/**
* Intento de registro de una tarjeta ya existente
* @author ajrueda
*/
public class TarjetaYaRegistrada extends RuntimeException {
public TarjetaYaRegistrada() {
}
}
/*
* 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.objetosvalor;
/**
* Simple random token for autorization
* NO SE USA EN EL PROYECTO POR EL MOMENTO
* @author ajrueda
*/
/*
public class Token {
public final long id;
public Token() { id = 0; }
private Token(long id) {
this.id = id;
}
public static Token generarAleatorio() {
return new Token(new Random().nextLong());
}
}
*/
\ No newline at end of file
/*
* 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 es.ujaen.dae.ujacoin.excepciones.TarjetaYaRegistrada;
import es.ujaen.dae.ujacoin.excepciones.TarjetaNoRegistrada;
import es.ujaen.dae.ujacoin.excepciones.CuentaNoRegistrada;
import es.ujaen.dae.ujacoin.entidades.Cliente;
import es.ujaen.dae.ujacoin.entidades.Cuenta;
import es.ujaen.dae.ujacoin.entidades.Tarjeta;
import es.ujaen.dae.ujacoin.entidades.movimientos.Ingreso;
import es.ujaen.dae.ujacoin.entidades.movimientos.Reintegro;
import es.ujaen.dae.ujacoin.entidades.movimientos.TransferenciaEmitida;
import es.ujaen.dae.ujacoin.entidades.movimientos.TransferenciaRecibida;
import es.ujaen.dae.ujacoin.excepciones.ClienteNoRegistrado;
import es.ujaen.dae.ujacoin.excepciones.ClienteYaRegistrado;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.TreeMap;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Positive;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
/**
* Clase con los servicios del banco virtual de UjaCoins
* Ojo: no se han implementado mecanismos de seguridad; puede usarse cualquier
* servicio sin realizar autenticación por parte del cliente
* @author ajrueda
*/
@Service
@Validated
public class ServicioUjaCoin {
/** Mapa con la lista de clientes ordenada por DNI */
Map<String, Cliente> clientes;
/** Mapa con la lista de cuentas ordenada por número */
Map<String, Cuenta> cuentas;
public ServicioUjaCoin() {
clientes = new TreeMap<>();
cuentas = new TreeMap<>();
}
/**
* Dar de alta cliente y crear una cuenta asociada
* @param cliente el cliente a dar de alta
* @return la cuenta asociada al cliente
*/
public Cuenta altaCliente(@NotNull @Valid Cliente cliente) {
if (clientes.containsKey(cliente.getDni())) {
throw new ClienteYaRegistrado();
}
// Registrar cliente
clientes.put(cliente.getDni(), cliente);
// Crear y registrar cuenta
Cuenta cuenta = crearCuenta(cliente);
cuentas.put(cuenta.getNum(), cuenta);
return cuenta;
}
/**
* Realiza un login de un cliente
* @param dni el DNI del cliente
* @param clave la clave de acceso
* @return el objeto de la clase Cliente asociado
*/
public Optional<Cliente> loginCliente(@NotBlank String dni, @NotBlank String clave) {
return Optional.ofNullable(clientes.get(dni)).filter((cliente)->cliente.claveValida(clave));
}
/**
* Crear una cuenta adicional para el cliente
* @param dni el DNI delcliente
* @return la cuenta creada
*/
public Cuenta crearCuenta(@NotBlank String dni) {
Cliente cliente = Optional.ofNullable(clientes.get(dni)).orElseThrow(ClienteNoRegistrado::new);
return crearCuenta(cliente);
}
/**
* Registrar una nueva tarjeta del cliente
* @param dni el DNI del cliente
* @param tarjeta la tarjeta a registrar
*/
public void registrarTarjeta(@NotBlank String dni, @NotNull @Valid Tarjeta tarjeta) {
Cliente cliente = Optional.ofNullable(clientes.get(dni)).orElseThrow(ClienteNoRegistrado::new);
cliente.verTarjeta(tarjeta.getNum()).ifPresent(x -> { throw new TarjetaYaRegistrada(); } );
cliente.nuevaTarjeta(tarjeta);
}
/**
* Devolver las cuentas de un cliente dado
* @param dni el DNI del cliente
* @return la lista de cuentas
*/
public List<Cuenta> verCuentas(@NotBlank String dni) {
Cliente cliente = Optional.ofNullable(clientes.get(dni)).orElseThrow(ClienteNoRegistrado::new);
return cliente.verCuentas();
}
/**
* Devolver las tarjetas registradas por el usuario
* @param dni el DNI del cliente
* @return la lista de tarjetas
*/
public List<Tarjeta> verTarjetas(@NotBlank String dni) {
Cliente cliente = Optional.ofNullable(clientes.get(dni)).orElseThrow(ClienteNoRegistrado::new);
return cliente.verTarjetas();
}
/**
* Realizar un ingreso en cuenta a partir de una tarjeta
* @param numCuenta el número de la cuenta donde se ingresa 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)
*/
public void ingreso(@NotBlank String numCuenta, @NotBlank String numTarjeta, @Positive float importe) {
Cuenta cuenta = Optional.ofNullable(cuentas.get(numCuenta))
.orElseThrow(CuentaNoRegistrada::new);
Tarjeta tarjeta = cuenta.getTitular().verTarjeta(numTarjeta)
.orElseThrow(TarjetaNoRegistrada::new);
cuenta.nuevoMovimiento(new Ingreso(tarjeta, importe));
}
/**
* Realizar un reintegro desde la cuenta a una tarjeta dada
* @param numCuenta el número de la cuenta desde donde se retira el dinero
* @param numTarjeta el número de la tarjeta donde se hace el ingreso
* @param importe el importe a retirar
*/
public void reintegro(@NotBlank String numCuenta, @NotBlank String numTarjeta, @Positive float importe) {
Cuenta cuenta = Optional.ofNullable(cuentas.get(numCuenta))
.orElseThrow(CuentaNoRegistrada::new);
Tarjeta tarjeta = cuenta.getTitular().verTarjeta(numTarjeta)
.orElseThrow(TarjetaNoRegistrada::new);
cuenta.nuevoMovimiento(new Reintegro(tarjeta, importe));
}
/**
* Realizar una transferencia entre dos cuentas
* @param numCuentaOrigen el número de la cuenta origen
* @param numCuentaDestino el número de la cuenta destino
* @param importe el importe a transferir
*/
public void transferencia(@NotBlank String numCuentaOrigen, @NotBlank String numCuentaDestino, @Positive float importe) {
Cuenta cuentaOrigen = Optional.ofNullable(cuentas.get(numCuentaOrigen))
.orElseThrow(CuentaNoRegistrada::new);
Cuenta cuentaDestino = Optional.ofNullable(cuentas.get(numCuentaDestino))
.orElseThrow(CuentaNoRegistrada::new);
cuentaOrigen.nuevoMovimiento(new TransferenciaEmitida(cuentaDestino, importe));
cuentaDestino.nuevoMovimiento(new TransferenciaRecibida(cuentaOrigen, importe));
}
// Crear una cuenta para el cliente indicado con un número no asignado
private Cuenta crearCuenta(Cliente cliente) {
// Generar número de cuenta de 10 dígitos aleatorio y no usado previamente
String numCuenta;
do {
numCuenta = Long.toString((new Random().nextLong() % 9000000000L) + 1000000000L);
} while (cuentas.containsKey(numCuenta));
Cuenta cuenta = new Cuenta(numCuenta, cliente);
cliente.nuevaCuenta(cuenta);
return cuenta;
}
}
/*
* 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.util;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
/**
*
* @author admin
*/
public class CodificadorMd5 {
private CodificadorMd5() {
}
public static String codificar(String cadena) {
String cadenaCodificada = null;
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(cadena.getBytes());
cadenaCodificada = Base64.getEncoder().withoutPadding().encodeToString(md.digest());
}
catch(NoSuchAlgorithmException e) {
// No debe ocurrir puesto que MD5 es un algoritmo que existe en la
// implementación Java estándar
}
return cadenaCodificada;
}
}
/*
* 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.util;
/**
*
* @author ajrueda
*/
public class ExprReg {
private ExprReg() {}
public static final String DNI = "\\d{8}[A-HJ-NP-TV-Z]";
public static final String TLF = "^(\\+34|0034|34)?[6789]\\d{8}$";
public static final String NUM_CUENTA = "\\d{10}";
public static final String NUM_TARJETA =
"^(?:(?<visa>4[0-9]{12}(?:[0-9]{3})?)|" +
"(?<mastercard>5[1-5][0-9]{14})|" +
"(?<discover>6(?:011|5[0-9]{2})[0-9]{12})|" +
"(?<amex>3[47][0-9]{13})|" +
"(?<diners>3(?:0[0-5]|[68][0-9])?[0-9]{11})|" +
"(?<jcb>(?:2131|1800|35[0-9]{3})[0-9]{11}))$";
public static final String CVC = "\\d{3}";
}
/*
* 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.entidades;
import java.time.LocalDate;
import java.util.List;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
/**
* Test para clase Cliente
* @author ajrueda
*/
public class ClienteTest {
public ClienteTest() {
}
@Test
void testValidacionCliente() {
String clave = "juanee90";
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);
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
Set<ConstraintViolation<Cliente>> violations = validator.validate(cliente);
Assertions.assertThat(violations).isEmpty();
}
@Test
void testComprobacionClave() {
String clave = "juanee90";
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);
Assertions.assertThat(cliente.claveValida(clave)).isTrue();
}
@Test
void testAnadirTarjeta() {
String clave = "juanee90";
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);
Tarjeta tarjeta = new Tarjeta("5500000000000004", cliente.getNombre(), LocalDate.of(2022, 12, 1), "365");
cliente.nuevaTarjeta(tarjeta);
List<Tarjeta> tarjetas = cliente.verTarjetas();
Assertions.assertThat(tarjetas.size()).isEqualTo(1);
Assertions.assertThat(tarjetas.get(0).getNum()).isEqualTo(tarjeta.getNum());
}
}
/*
* 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.entidades;
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.TransferenciaRecibida;
import java.time.LocalDate;
import java.util.List;
import org.assertj.core.api.Assertions;
import org.junit.Test;
/**
*
* @author ajrueda
*/
public class CuentaTest {
@Test
public void testNuevoMovimiento() {
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");
// Probar ingreso en cuenta
Tarjeta tarjeta = new Tarjeta("5495370181529932", cliente.getNombre(), LocalDate.of(2022, 12, 1), "365");
cliente.nuevaTarjeta(tarjeta);
Cuenta cuenta = new Cuenta("12345678910", cliente);
Movimiento ingreso = new Ingreso(tarjeta, 1000);
cuenta.nuevoMovimiento(ingreso);
Assertions.assertThat(cuenta.getSaldo()).isEqualTo(1000);
Assertions.assertThat(cuenta.listarMovimientos()).hasSize(1);
Assertions.assertThat(cuenta.listarMovimientos().get(0)).isSameAs(ingreso);
// Probar transferencia entre dos cuentas
Cuenta cuenta2 = new Cuenta("9898989898", cliente);
int importeTransferencia = 500;
Movimiento transferenciaEmitida = new TransferenciaEmitida(cuenta2, importeTransferencia);
cuenta.nuevoMovimiento(transferenciaEmitida);
Movimiento transferenciaRecibida = new TransferenciaRecibida(cuenta, importeTransferencia);
cuenta2.nuevoMovimiento(transferenciaRecibida);
Assertions.assertThat(cuenta.getSaldo()).isEqualTo(500);
Assertions.assertThat(cuenta.listarMovimientos()).hasSize(2);
Assertions.assertThat(cuenta.listarMovimientos().get(1)).isSameAs(transferenciaEmitida);
Assertions.assertThat(cuenta2.getSaldo()).isEqualTo(500);
Assertions.assertThat(cuenta2.listarMovimientos().size()).isEqualTo(1);
Assertions.assertThat(cuenta2.listarMovimientos().get(0)).isSameAs(transferenciaRecibida);
}
}
/*
* 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 es.ujaen.dae.ujacoin.entidades.Cliente;
import es.ujaen.dae.ujacoin.entidades.Cuenta;
import es.ujaen.dae.ujacoin.entidades.Tarjeta;
import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
import javax.validation.ConstraintViolationException;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.MethodMode;
/**
*
* @author ajrueda
*/
//@Disabled
@SpringBootTest(classes = es.ujaen.dae.ujacoin.app.UjaCoinApp.class)
public class ServicioUjaCoinTest {
@Autowired
ServicioUjaCoin servicioUjaCoin;
@Test
public void testAccesoServicioUjaCoin() {
Assertions.assertThat(servicioUjaCoin).isNotNull();
}
@Test
@DirtiesContext(methodMode = MethodMode.AFTER_METHOD)
public void testAltaClienteInvalido() {
// Cliente con e-mail incorrecto!!!
Cliente cliente = new Cliente(
"11995667D",
"Juan España España",
LocalDate.of(1990, 11, 1),
"Cl La Luz, 13 - Jaén",
"988674533",
"jeegmail.com",
"clave");
Assertions.assertThatThrownBy(() -> {
servicioUjaCoin.altaCliente(cliente); })
.isInstanceOf(ConstraintViolationException.class);
}
@Test
@DirtiesContext(methodMode = MethodMode.AFTER_METHOD)
public void testAltaYLoginClienteCuenta() {
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");
Cuenta cuenta = servicioUjaCoin.altaCliente(cliente);
Optional<Cliente> clienteLogin = servicioUjaCoin.loginCliente(cliente.getDni(), "clave");
Assertions.assertThat(clienteLogin.isPresent()).isTrue();
Assertions.assertThat(clienteLogin.get()).isEqualTo(cliente);
}
@Test
@DirtiesContext(methodMode = MethodMode.AFTER_METHOD)
public void testIngreso() {
// 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");
Cuenta cuenta = servicioUjaCoin.altaCliente(cliente);
Cliente clienteLogin = servicioUjaCoin.loginCliente(cliente.getDni(), "clave").get();
// Añadir una tarjeta
Tarjeta tarjeta = new Tarjeta("4111111111111111", cliente.getNombre(), LocalDate.of(2022, 12, 1), "365");
servicioUjaCoin.registrarTarjeta(clienteLogin.getDni(), tarjeta);
clienteLogin.nuevaTarjeta(tarjeta);
// Obtener cuenta
List<Cuenta> cuentas = servicioUjaCoin.verCuentas(clienteLogin.getDni());
Assertions.assertThat(cuentas).hasSize(1);
// Realizar ingreso y comprobar estado de la cuenta
servicioUjaCoin.ingreso(cuentas.get(0).getNum(), tarjeta.getNum(), 1000);
Assertions.assertThat(cuentas.get(0).listarMovimientosDesdeHasta(null, null)).hasSize(1);
Assertions.assertThat(cuentas.get(0).getSaldo()).isEqualTo(1000);
}
}
<mxfile host="app.diagrams.net" modified="2020-10-14T17:01:13.664Z" agent="5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.80 Safari/537.36" etag="2To3tcnGGGotBWitwj_X" version="13.7.9" type="device"><diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1">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</diagram></mxfile>
\ No newline at end of file
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