Initial Commit
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
target
|
||||
.idea
|
||||
99
pom.xml
Executable file
99
pom.xml
Executable file
@@ -0,0 +1,99 @@
|
||||
<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/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>xyz.danielcortes</groupId>
|
||||
<artifactId>fx</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>13</maven.compiler.source>
|
||||
<maven.compiler.target>13</maven.compiler.target>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<!-- JAVAFX -->
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-controls</artifactId>
|
||||
<version>13</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Math Parser -->
|
||||
<dependency>
|
||||
<groupId>org.mariuszgromada.math</groupId>
|
||||
<artifactId>MathParser.org-mXparser</artifactId>
|
||||
<version>4.3.3</version>
|
||||
</dependency>
|
||||
|
||||
<!-- DB -->
|
||||
<dependency>
|
||||
<groupId>org.mariadb.jdbc</groupId>
|
||||
<artifactId>mariadb-java-client</artifactId>
|
||||
<version>2.4.4</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JUnit -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.5.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- LOG -->
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.2.3</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-dependencies</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.1.2</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<addClasspath>true</addClasspath>
|
||||
<classpathPrefix>dependency/</classpathPrefix>
|
||||
<mainClass>xyz.danielcortes.Launcher</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>src/assembly/deployer.xml</descriptor>
|
||||
</descriptors>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>install</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
25
src/assembly/deployer.xml
Executable file
25
src/assembly/deployer.xml
Executable file
@@ -0,0 +1,25 @@
|
||||
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
|
||||
<id>dist</id>
|
||||
<formats>
|
||||
<format>tar.gz</format>
|
||||
<format>zip</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>true</includeBaseDirectory>
|
||||
<files>
|
||||
<file>
|
||||
<source>${project.build.directory}/${project.build.finalName}.jar</source>
|
||||
</file>
|
||||
</files>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>${project.build.directory}/dependency</directory>
|
||||
<outputDirectory>/dependency</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${project.basedir}/src/sql</directory>
|
||||
<outputDirectory>/sql</outputDirectory>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
87
src/main/java/xyz/danielcortes/App.java
Executable file
87
src/main/java/xyz/danielcortes/App.java
Executable file
@@ -0,0 +1,87 @@
|
||||
package xyz.danielcortes;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.stage.Stage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import xyz.danielcortes.egresos.EgresoController;
|
||||
import xyz.danielcortes.egresos.EgresoDAO;
|
||||
import xyz.danielcortes.egresos.EgresoRepo;
|
||||
import xyz.danielcortes.egresos.EgresoScene;
|
||||
import xyz.danielcortes.ingresos.IngresoScene;
|
||||
import xyz.danielcortes.menubar.AppMenu;
|
||||
import xyz.danielcortes.turno.TurnoDAO;
|
||||
import xyz.danielcortes.turno.TurnoRepo;
|
||||
import xyz.danielcortes.turno.TurnoToolbar;
|
||||
import xyz.danielcortes.turno.TurnoToolbarController;
|
||||
import xyz.danielcortes.users.LoginController;
|
||||
import xyz.danielcortes.users.LoginScene;
|
||||
import xyz.danielcortes.users.UserDAO;
|
||||
import xyz.danielcortes.users.UserRepo;
|
||||
|
||||
public class App extends Application {
|
||||
static final Logger logger = LoggerFactory.getLogger(App.class);
|
||||
|
||||
@Override
|
||||
public void start(Stage stage) {
|
||||
DB db = new DB();
|
||||
|
||||
UserDAO userDAO = new UserDAO(db);
|
||||
EgresoDAO egresoDAO = new EgresoDAO(db);
|
||||
TurnoDAO turnoDAO = new TurnoDAO(db);
|
||||
|
||||
UserRepo userRepo = new UserRepo(userDAO);
|
||||
EgresoRepo egresoRepo = new EgresoRepo(egresoDAO);
|
||||
TurnoRepo turnoRepo = new TurnoRepo( turnoDAO);
|
||||
|
||||
UndoRedoManager undoRedoManager = new UndoRedoManager();
|
||||
|
||||
AppMenu appMenu = new AppMenu();
|
||||
TurnoToolbar turnoToolbar = new TurnoToolbar();
|
||||
LoginScene loginScene = new LoginScene();
|
||||
EgresoScene egresoScene = new EgresoScene(turnoToolbar, appMenu);
|
||||
|
||||
LoginController loginController = new LoginController(loginScene, userRepo);
|
||||
TurnoToolbarController turnoToolbarController = new TurnoToolbarController(turnoToolbar, turnoRepo);
|
||||
EgresoController egresoController = new EgresoController(egresoScene, egresoRepo, turnoRepo, undoRedoManager);
|
||||
|
||||
// turnoToolbarController.addTurnoChangeListener(egresoController::onTurnoChange);
|
||||
//
|
||||
// turnoToolbarController.addSaveListener(() -> {
|
||||
// turnoRepo.commit();
|
||||
// userRepo.commit();
|
||||
// egresoRepo.commit();
|
||||
// undoRedoManager.clear();
|
||||
// });
|
||||
//
|
||||
// loginController.addLoginListener(user -> {
|
||||
// stage.hide();
|
||||
// stage.setScene(egresoScene.getScene());
|
||||
//
|
||||
// stage.setWidth(1000);
|
||||
// stage.setHeight(600);
|
||||
// stage.centerOnScreen();
|
||||
//
|
||||
// stage.setTitle("Egreso");
|
||||
// stage.show();
|
||||
// });
|
||||
//
|
||||
// appMenu.addEgresosListener(() -> {
|
||||
// stage.setScene(egresoScene.getScene());
|
||||
// stage.setTitle("Egreso");
|
||||
// });
|
||||
//
|
||||
stage.setScene(new IngresoScene(turnoToolbar, appMenu).getScene());
|
||||
|
||||
stage.setWidth(1000);
|
||||
stage.setHeight(600);
|
||||
stage.centerOnScreen();
|
||||
|
||||
stage.setTitle("Ingresos");
|
||||
stage.show();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
launch();
|
||||
}
|
||||
}
|
||||
6
src/main/java/xyz/danielcortes/Command.java
Executable file
6
src/main/java/xyz/danielcortes/Command.java
Executable file
@@ -0,0 +1,6 @@
|
||||
package xyz.danielcortes;
|
||||
|
||||
public interface Command {
|
||||
void execute();
|
||||
void undo();
|
||||
}
|
||||
365
src/main/java/xyz/danielcortes/DAO.java
Executable file
365
src/main/java/xyz/danielcortes/DAO.java
Executable file
@@ -0,0 +1,365 @@
|
||||
package xyz.danielcortes;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import xyz.danielcortes.egresos.Egreso;
|
||||
import xyz.danielcortes.egresos.TipoEgreso;
|
||||
|
||||
/**
|
||||
* Este objeto se utiliza como interfaz para realizar queries a una entidad a la base de datos.
|
||||
*
|
||||
* @param <T> Entidad la cual se obtendrá de estas queries.
|
||||
*/
|
||||
public abstract class DAO<T extends Entity> {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(DAO.class);
|
||||
|
||||
protected DB db;
|
||||
protected String table;
|
||||
protected List<String> columns;
|
||||
|
||||
/**
|
||||
* Crea un objeto DAO para realizar queries a la base de datos.
|
||||
*
|
||||
* @param db DB que entrega conexiones a la base de datos
|
||||
* @param table Tabla que a la que el objeto hará queries
|
||||
* @param columns Columnas que tiene la tabla El único requisito es que el primer elemento
|
||||
* represente el id de la tabla.
|
||||
*/
|
||||
public DAO(DB db, String table, List<String> columns) {
|
||||
this.db = db;
|
||||
this.table = table;
|
||||
this.columns = columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Entrega las columnas del objeto en la base de datos
|
||||
* <p>
|
||||
* Por ejemplo si es que se definieron las columas id, nombre y tipo este metodo debe entregar una
|
||||
* lista con el valor de esas columnas del objeto entregado, en orden, en una lista.
|
||||
* <p>
|
||||
* El id siempre debe ser el primer valor
|
||||
*
|
||||
* @param entity Entidad desde la cual se necesitan obtener las columnas
|
||||
* @return Una lista con las columnas de la entidad.
|
||||
*/
|
||||
protected abstract List<Object> getColumnsValues(T entity);
|
||||
|
||||
/**
|
||||
* Mapea un ResultSet a una entidad
|
||||
*
|
||||
* @param rs ResultSet el cual ya tendrá el cursor sobre la entidad requerida
|
||||
* @return La entidad que contenía el ResultSet
|
||||
* @throws SQLException Si es que la label pasada al result set no existe.
|
||||
*/
|
||||
protected abstract T mapToEntity(ResultSet rs) throws SQLException;
|
||||
|
||||
/**
|
||||
* Obtiene un solo elemento que la query devuelva.
|
||||
*
|
||||
* @param query Query que ejecutar
|
||||
* @return La entidad que la query encontró, si no encontró ninguna, se retornara un null
|
||||
*/
|
||||
protected T fetchSingle(String query) {
|
||||
return fetchSingle(query, Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtiene un solo elemento que la query devuelva.
|
||||
*
|
||||
* @param query Query que ejecutar
|
||||
* @param parameters Parámetros a pasar a la query.
|
||||
* @return La entidad que la query encontró, si no encontró ninguna, se retornara un null
|
||||
*/
|
||||
protected T fetchSingle(String query, List<Object> parameters) {
|
||||
try (
|
||||
Connection con = db.getConnection();
|
||||
PreparedStatement st = con.prepareStatement(query);
|
||||
) {
|
||||
|
||||
for (int i = 0; i < parameters.size(); i++) {
|
||||
st.setObject(i + 1, parameters.get(i));
|
||||
}
|
||||
|
||||
try (ResultSet rs = st.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
return mapToEntity(rs);
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
log.error("Error al realizar query {} con parámetros {}", query, parameters, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtiene una lista de elementos que la query devuelva.
|
||||
*
|
||||
* @param query Query que ejecutar
|
||||
* @return La lista de entidades que la query encontró, si no encontró ninguna, sera una lista
|
||||
* vacía
|
||||
*/
|
||||
protected List<T> fetchMany(String query) {
|
||||
return fetchMany(query, Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtiene una lista de elementos que la query devuelva.
|
||||
*
|
||||
* @param query Query que ejecutar
|
||||
* @param parameters Parámetros a pasar a la query.
|
||||
* @return La lista de entidades que la query encontró, si no encontró ninguna, sera una lista
|
||||
* vacía
|
||||
*/
|
||||
protected List<T> fetchMany(String query, List<Object> parameters) {
|
||||
List<T> list = new ArrayList<>();
|
||||
try (
|
||||
Connection con = db.getConnection();
|
||||
PreparedStatement st = con.prepareStatement(query);
|
||||
) {
|
||||
for (int i = 0; i < parameters.size(); i++) {
|
||||
st.setObject(i + 1, parameters.get(i));
|
||||
}
|
||||
try (ResultSet rs = st.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
list.add(mapToEntity(rs));
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
log.error("Error al obtener todos los egresos", e);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Busca una entidad dada su id
|
||||
*
|
||||
* @param id Id de la entidad buscada
|
||||
* @return La entidad encontrada, si no se encontró, retornara un null.
|
||||
*/
|
||||
public T findByID(String id) {
|
||||
//noinspection SqlResolve
|
||||
String query = "select * from " + table + " where " + columns.get(0) + " = ? limit 1";
|
||||
return fetchSingle(query, List.of(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Busca todas las entidades de la tabla
|
||||
*
|
||||
* @return La lista de entidades buscadas, si no había ninguna, sera una lista vacía.
|
||||
*/
|
||||
public List<T> findAll() {
|
||||
return fetchMany("select * from " + table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserta una lista de entidades
|
||||
*
|
||||
* @param entities Entidades a insertar.
|
||||
*/
|
||||
public void insert(Collection<T> entities) {
|
||||
if (entities.size() <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
try (
|
||||
Connection con = db.getConnection();
|
||||
PreparedStatement st = con.prepareStatement(buildInsertQuery(entities.size()));
|
||||
) {
|
||||
int i = 1;
|
||||
for (T entity : entities) {
|
||||
for (Object column : getColumnsValues(entity)) {
|
||||
st.setObject(i++, column);
|
||||
}
|
||||
}
|
||||
st.execute();
|
||||
} catch (SQLException e) {
|
||||
log.error("Error al insertar la entidad a la tabla {}", table, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Actualiza una lista de entidades
|
||||
*
|
||||
* @param entities Entidades a actualizar
|
||||
*/
|
||||
public void update(Collection<T> entities) {
|
||||
if (entities.size() <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
try (
|
||||
Connection con = db.getConnection();
|
||||
PreparedStatement st = con.prepareStatement(buildUpdateQuery());
|
||||
) {
|
||||
for (T entity : entities) {
|
||||
st.clearParameters();
|
||||
List<Object> columnsValues = getColumnsValues(entity);
|
||||
for (int i = 1; i < columnsValues.size(); i++) {
|
||||
st.setObject(i, columnsValues.get(i));
|
||||
}
|
||||
st.setObject(columnsValues.size(), columnsValues.get(0));
|
||||
st.addBatch();
|
||||
}
|
||||
st.executeBatch();
|
||||
} catch (SQLException e) {
|
||||
log.error("Error al actualizar las entidad de la tabla {}", table, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Elimina una lista de entidades
|
||||
*
|
||||
* @param entities Entidades a eliminar
|
||||
*/
|
||||
public void delete(Collection<T> entities) {
|
||||
if (entities.size() <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
try (
|
||||
Connection con = db.getConnection();
|
||||
PreparedStatement st = con.prepareStatement(buildDeleteQuery(entities.size()));
|
||||
) {
|
||||
int i = 1;
|
||||
for (T entity : entities) {
|
||||
st.setObject(i++, getColumnsValues(entity).get(0));
|
||||
}
|
||||
st.execute();
|
||||
} catch (SQLException e) {
|
||||
log.error("Error al eliminar egresos", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Crea una query para insertar una lista de elementos.
|
||||
* <p>
|
||||
* Esta query tendrá la forma de:
|
||||
* <p>
|
||||
* insert into table (col1, col2, col3, col4) values (?, ?, ?, ?), (?, ?, ?, ?), (?, ?, ?, ?)
|
||||
*
|
||||
* @param size Cantidad de entidades que se insertaran usando esta query
|
||||
* @return El sql necesario para insertar una serie de elementos.
|
||||
*/
|
||||
protected String buildInsertQuery(int size) {
|
||||
StringBuilder sql = new StringBuilder();
|
||||
// insert into
|
||||
sql.append("insert into ");
|
||||
// insert into table
|
||||
sql.append(table);
|
||||
// insert into table (
|
||||
sql.append(" (");
|
||||
// insert into table (col1, col2, col3, col4
|
||||
sql.append(String.join(", ", columns));
|
||||
// insert into table (col1, col2, col3, col4)
|
||||
sql.append(") ");
|
||||
// insert into table (col1, col2, col3, col4) values
|
||||
sql.append("values ");
|
||||
for (int i = 0; i < size; i++) {
|
||||
// (
|
||||
sql.append("(");
|
||||
// (?, ?, ?, ?
|
||||
for (int j = 0; j < columns.size(); j++) {
|
||||
sql.append("?");
|
||||
if (j < columns.size() - 1) {
|
||||
sql.append(", ");
|
||||
}
|
||||
}
|
||||
// (?, ?, ?, ?)
|
||||
sql.append(")");
|
||||
if (i < size - 1) {
|
||||
// (?, ?, ?, ?),
|
||||
sql.append(", ");
|
||||
}
|
||||
}
|
||||
|
||||
log.info("Builder insert SQL {}", sql);
|
||||
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Crea una query para actualizar una entidad.
|
||||
* <p>
|
||||
* Esta query tendrá la forma de:
|
||||
* <p>
|
||||
* update table set col2 = ?, col3 = ?, col4 = ? where col1 = ?
|
||||
*
|
||||
* @return El sql necesario para actualizar una entidad.
|
||||
*/
|
||||
protected String buildUpdateQuery() {
|
||||
StringBuilder sql = new StringBuilder();
|
||||
// update
|
||||
sql.append("update ");
|
||||
// update table
|
||||
sql.append(table);
|
||||
// update table set
|
||||
sql.append(" set ");
|
||||
// update table set col2 = ?, col3 = ?, col4 = ?
|
||||
for (int i = 1; i < columns.size(); i++) {
|
||||
sql.append(columns.get(i));
|
||||
sql.append(" = ?");
|
||||
if (i < columns.size() - 1) {
|
||||
sql.append(", ");
|
||||
} else {
|
||||
sql.append(" ");
|
||||
}
|
||||
}
|
||||
// update table set col2 = ?, col3 = ?, col4 = ? where
|
||||
sql.append("where ");
|
||||
// update table set col2 = ?, col3 = ?, col4 = ? where col1
|
||||
sql.append(columns.get(0));
|
||||
// update table set col2 = ?, col3 = ?, col4 = ? where col1 = ?
|
||||
sql.append(" = ?");
|
||||
|
||||
log.info("Builder update SQL {}", sql);
|
||||
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Crea una query para eliminar una serie de entidades por su id.
|
||||
* <p>
|
||||
* Esta query tendrá la forma de:
|
||||
* <p>
|
||||
* delete from table where id in (?, ?, ?, ?, ?)
|
||||
*
|
||||
* @param size Cantidad de entidades que se eliminaran usando esta query
|
||||
* @return El sql necesario para eliminar una serie de entidades por su id
|
||||
*/
|
||||
protected String buildDeleteQuery(int size) {
|
||||
StringBuilder sql = new StringBuilder();
|
||||
// delete from
|
||||
sql.append("delete from ");
|
||||
// delete from table
|
||||
sql.append(table);
|
||||
// delete from table where
|
||||
sql.append(" where ");
|
||||
// delete from table where id
|
||||
sql.append(columns.get(0));
|
||||
// delete from table where id in (
|
||||
sql.append(" in (");
|
||||
// delete from table where id in (?, ?, ?, ?, ?
|
||||
for (int i = 0; i < size; i++) {
|
||||
sql.append("?");
|
||||
if (i < size - 1) {
|
||||
sql.append(", ");
|
||||
}
|
||||
}
|
||||
// delete from table where id in (?, ?, ?, ?, ?)
|
||||
sql.append(")");
|
||||
|
||||
log.info("Builder delete SQL {}", sql);
|
||||
|
||||
return sql.toString();
|
||||
}
|
||||
}
|
||||
22
src/main/java/xyz/danielcortes/DB.java
Executable file
22
src/main/java/xyz/danielcortes/DB.java
Executable file
@@ -0,0 +1,22 @@
|
||||
package xyz.danielcortes;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class DB {
|
||||
private String userName = "root";
|
||||
private String password = "ff9800s_a_d";
|
||||
private String url = "jdbc:mysql://localhost:3306/simplefx";
|
||||
|
||||
public DB(){}
|
||||
|
||||
public Connection getConnection() {
|
||||
try {
|
||||
return DriverManager.getConnection(url, userName, password);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
45
src/main/java/xyz/danielcortes/Entity.java
Executable file
45
src/main/java/xyz/danielcortes/Entity.java
Executable file
@@ -0,0 +1,45 @@
|
||||
package xyz.danielcortes;
|
||||
|
||||
import java.util.UUID;
|
||||
import xyz.danielcortes.egresos.Egreso;
|
||||
|
||||
public abstract class Entity {
|
||||
protected final String id;
|
||||
|
||||
public Entity() {
|
||||
this.id = UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
public Entity(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getId(){
|
||||
return id;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
if (id != null) {
|
||||
return id.hashCode();
|
||||
} else {
|
||||
return super.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof Entity)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Entity other = (Entity) o;
|
||||
|
||||
if (id == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return id.equals(other.getId());
|
||||
}
|
||||
}
|
||||
7
src/main/java/xyz/danielcortes/Launcher.java
Executable file
7
src/main/java/xyz/danielcortes/Launcher.java
Executable file
@@ -0,0 +1,7 @@
|
||||
package xyz.danielcortes;
|
||||
|
||||
public class Launcher {
|
||||
public static void main(String[] args) {
|
||||
App.main(args);
|
||||
}
|
||||
}
|
||||
38
src/main/java/xyz/danielcortes/MathStringConverter.java
Executable file
38
src/main/java/xyz/danielcortes/MathStringConverter.java
Executable file
@@ -0,0 +1,38 @@
|
||||
package xyz.danielcortes;
|
||||
|
||||
import javafx.util.StringConverter;
|
||||
import org.mariuszgromada.math.mxparser.Expression;
|
||||
|
||||
public class MathStringConverter extends StringConverter<Integer> {
|
||||
|
||||
@Override
|
||||
public String toString(Integer value) {
|
||||
if (value == null) {
|
||||
return "0";
|
||||
}
|
||||
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer fromString(String value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
value = value.trim();
|
||||
|
||||
if (value.length() <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int result = 0;
|
||||
|
||||
Expression expression = new Expression(value);
|
||||
if (expression.checkSyntax()) {
|
||||
result = (int) Math.floor(expression.calculate());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
23
src/main/java/xyz/danielcortes/Pair.java
Executable file
23
src/main/java/xyz/danielcortes/Pair.java
Executable file
@@ -0,0 +1,23 @@
|
||||
package xyz.danielcortes;
|
||||
|
||||
public class Pair<L, R> {
|
||||
private L left;
|
||||
private R right;
|
||||
|
||||
private Pair(){}
|
||||
|
||||
public Pair of(L left, R right){
|
||||
var pair = new Pair();
|
||||
pair.left = left;
|
||||
pair.right = right;
|
||||
return pair;
|
||||
}
|
||||
|
||||
public L getLeft() {
|
||||
return left;
|
||||
}
|
||||
|
||||
public R getRight() {
|
||||
return right;
|
||||
}
|
||||
}
|
||||
150
src/main/java/xyz/danielcortes/Repo.java
Executable file
150
src/main/java/xyz/danielcortes/Repo.java
Executable file
@@ -0,0 +1,150 @@
|
||||
package xyz.danielcortes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public abstract class Repo<T extends Entity> {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(Repo.class);
|
||||
|
||||
protected DAO<T> dao;
|
||||
protected Map<String, T> toAdd;
|
||||
protected Map<String, T> toRemove;
|
||||
protected Map<String, T> toUpdate;
|
||||
|
||||
public Repo(DAO<T> dao) {
|
||||
this.dao = dao;
|
||||
toAdd = new HashMap<>();
|
||||
toRemove = new HashMap<>();
|
||||
toUpdate = new HashMap<>();
|
||||
}
|
||||
|
||||
public T getById(String id) {
|
||||
if(toAdd.containsKey(id)){
|
||||
return toAdd.get(id);
|
||||
}
|
||||
|
||||
if(toUpdate.containsKey(id)) {
|
||||
return toUpdate.get(id);
|
||||
}
|
||||
|
||||
var entity = dao.findByID(id);
|
||||
if(entity != null && !toRemove.containsKey(id)){
|
||||
return entity;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<T> getAll() {
|
||||
List<T> list = new ArrayList<>();
|
||||
|
||||
list.addAll(toAdd.values());
|
||||
list.addAll(toUpdate.values());
|
||||
|
||||
for(T entity: dao.findAll()) {
|
||||
if(!list.contains(entity) && !toRemove.containsKey(entity.getId())){
|
||||
list.add(entity);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Agrega una entidad
|
||||
* <p>
|
||||
* - Si es que la entidad se iba a eliminar se quitara de esa lista.
|
||||
* <p>
|
||||
* - Si no, se agregara normalmente.
|
||||
*
|
||||
* @param entity Entity a agregar
|
||||
*/
|
||||
public void add(T entity) {
|
||||
if (toRemove.get(entity.getId()) != null) {
|
||||
toRemove.remove(entity.getId());
|
||||
} else {
|
||||
toAdd.put(entity.getId(), entity);
|
||||
}
|
||||
|
||||
log.info("-".repeat(100));
|
||||
log.info("Entity added: " + entity);
|
||||
logCurrentStatus();
|
||||
log.info("-".repeat(100));
|
||||
}
|
||||
|
||||
/**
|
||||
* Elimina una entidad
|
||||
* <p>
|
||||
* - Si es que la entity se iba a agregar se quitara de esa lista.
|
||||
* <p>
|
||||
* - Si no, se eliminara normalmente.
|
||||
*
|
||||
* @param entity Entity a eliminar
|
||||
*/
|
||||
public void remove(T entity) {
|
||||
if (toAdd.get(entity.getId()) != null) {
|
||||
toAdd.remove(entity.getId());
|
||||
} else {
|
||||
toRemove.put(entity.getId(), entity);
|
||||
}
|
||||
|
||||
log.info("-".repeat(100));
|
||||
log.info("Egreso removed: " + entity);
|
||||
logCurrentStatus();
|
||||
log.info("-".repeat(100));
|
||||
}
|
||||
|
||||
/**
|
||||
* Actualiza una entity
|
||||
* <p>
|
||||
* - Si es que la entity se no se iba a agregar, se actualizara normalmente.
|
||||
* <p>
|
||||
* - Si la entity se iba a agregar, sera actualizado el de la lista de agregar.
|
||||
*
|
||||
* @param entity entity a actualizar
|
||||
*/
|
||||
public void update(T entity) {
|
||||
if (toAdd.get(entity.getId()) == null) {
|
||||
toUpdate.put(entity.getId(), entity);
|
||||
} else {
|
||||
toAdd.put(entity.getId(), entity);
|
||||
}
|
||||
|
||||
log.info("-".repeat(100));
|
||||
log.info("Egreso updated: " + entity);
|
||||
logCurrentStatus();
|
||||
log.info("-".repeat(100));
|
||||
}
|
||||
|
||||
public void commit() {
|
||||
log.info("-".repeat(100));
|
||||
log.info("Doing commit");
|
||||
logCurrentStatus();
|
||||
log.info("-".repeat(100));
|
||||
|
||||
dao.insert(toAdd.values());
|
||||
dao.update(toUpdate.values());
|
||||
dao.delete(toRemove.values());
|
||||
|
||||
toAdd.clear();
|
||||
toUpdate.clear();
|
||||
toRemove.clear();
|
||||
}
|
||||
|
||||
private void logCurrentStatus() {
|
||||
log.info("Current repo status");
|
||||
log.info("To Add:");
|
||||
toAdd.values().forEach(e -> log.info("{}", e));
|
||||
log.info("-".repeat(50));
|
||||
log.info("To Remove:");
|
||||
toRemove.values().forEach(e -> log.info("{}", e));
|
||||
log.info("-".repeat(50));
|
||||
log.info("To Update:");
|
||||
toUpdate.values().forEach(e -> log.info("{}", e));
|
||||
}
|
||||
}
|
||||
68
src/main/java/xyz/danielcortes/UndoRedoManager.java
Executable file
68
src/main/java/xyz/danielcortes/UndoRedoManager.java
Executable file
@@ -0,0 +1,68 @@
|
||||
package xyz.danielcortes;
|
||||
|
||||
import java.util.Stack;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class UndoRedoManager {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(UndoRedoManager.class);
|
||||
|
||||
private Stack<Command> undoStack;
|
||||
private Stack<Command> redoStack;
|
||||
|
||||
public UndoRedoManager() {
|
||||
undoStack = new Stack<>();
|
||||
redoStack = new Stack<>();
|
||||
}
|
||||
|
||||
public void execute(Command command) {
|
||||
command.execute();
|
||||
redoStack.clear();
|
||||
undoStack.push(command);
|
||||
|
||||
logUndoRedoStacks();
|
||||
}
|
||||
|
||||
public void undo() {
|
||||
if (!undoStack.empty()) {
|
||||
undoStack.peek().undo();
|
||||
redoStack.push(undoStack.pop());
|
||||
logUndoRedoStacks();
|
||||
}
|
||||
}
|
||||
|
||||
public void redo() {
|
||||
if (!redoStack.empty()) {
|
||||
redoStack.peek().execute();
|
||||
undoStack.push(redoStack.pop());
|
||||
logUndoRedoStacks();
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
undoStack.clear();
|
||||
redoStack.clear();
|
||||
|
||||
log.info("Cleared");
|
||||
}
|
||||
|
||||
private void logUndoRedoStacks() {
|
||||
log.info("-".repeat(100));
|
||||
log.info("Current Undo Redo Stack Status: ");
|
||||
|
||||
log.info("Undo Stack: ");
|
||||
for (Command command : undoStack) {
|
||||
log.info("{}", command);
|
||||
}
|
||||
|
||||
log.info("-".repeat(50));
|
||||
|
||||
log.info("Redo Stack: ");
|
||||
for (Command command : redoStack) {
|
||||
log.info("{}", command);
|
||||
}
|
||||
log.info("-".repeat(100));
|
||||
|
||||
}
|
||||
}
|
||||
66
src/main/java/xyz/danielcortes/egresos/Egreso.java
Executable file
66
src/main/java/xyz/danielcortes/egresos/Egreso.java
Executable file
@@ -0,0 +1,66 @@
|
||||
package xyz.danielcortes.egresos;
|
||||
|
||||
import xyz.danielcortes.Entity;
|
||||
|
||||
public final class Egreso extends Entity {
|
||||
|
||||
private final String nro;
|
||||
private final String descripcion;
|
||||
private final Integer valor;
|
||||
private final TipoEgreso tipo;
|
||||
private final String turnoID;
|
||||
|
||||
public Egreso(String nro, String descripcion, int valor, TipoEgreso tipo, String turnoID) {
|
||||
super();
|
||||
this.nro = nro;
|
||||
this.descripcion = descripcion;
|
||||
this.valor = valor;
|
||||
this.tipo = tipo;
|
||||
this.turnoID = turnoID;
|
||||
}
|
||||
|
||||
public Egreso(String id, String nro, String descripcion, int valor, TipoEgreso tipo, String turnoID) {
|
||||
super(id);
|
||||
this.nro = nro;
|
||||
this.descripcion = descripcion;
|
||||
this.valor = valor;
|
||||
this.tipo = tipo;
|
||||
this.turnoID = turnoID;
|
||||
}
|
||||
|
||||
public final String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public final String getNro() {
|
||||
return nro;
|
||||
}
|
||||
|
||||
public final String getDescripcion() {
|
||||
return descripcion;
|
||||
}
|
||||
|
||||
public final Integer getValor() {
|
||||
return valor;
|
||||
}
|
||||
|
||||
public final TipoEgreso getTipo() {
|
||||
return tipo;
|
||||
}
|
||||
|
||||
public final String getTurnoID() {
|
||||
return turnoID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Egreso{" +
|
||||
"id='" + id + '\'' +
|
||||
", nro='" + nro + '\'' +
|
||||
", descripcion='" + descripcion + '\'' +
|
||||
", valor=" + valor +
|
||||
", tipo=" + tipo +
|
||||
", turnoID='" + turnoID + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
85
src/main/java/xyz/danielcortes/egresos/EgresoController.java
Executable file
85
src/main/java/xyz/danielcortes/egresos/EgresoController.java
Executable file
@@ -0,0 +1,85 @@
|
||||
package xyz.danielcortes.egresos;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import xyz.danielcortes.Repo;
|
||||
import xyz.danielcortes.UndoRedoManager;
|
||||
import xyz.danielcortes.egresos.commands.AddEgresoCommand;
|
||||
import xyz.danielcortes.egresos.commands.RemoveEgresoCommand;
|
||||
import xyz.danielcortes.egresos.commands.UpdateEgresoCommand;
|
||||
import xyz.danielcortes.listeners.ObjectChangeListener;
|
||||
import xyz.danielcortes.turno.Turno;
|
||||
import xyz.danielcortes.turno.TurnoRepo;
|
||||
|
||||
public class EgresoController {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(EgresoController.class);
|
||||
|
||||
private Turno currentTurno;
|
||||
private UndoRedoManager undoRedoManager;
|
||||
private EgresoScene scene;
|
||||
private EgresoRepo egresoRepo;
|
||||
private TurnoRepo turnoRepo;
|
||||
|
||||
public EgresoController(EgresoScene scene, EgresoRepo egresoRepo, TurnoRepo turnoRepo, UndoRedoManager undoRedoManager) {
|
||||
this.egresoRepo = egresoRepo;
|
||||
this.turnoRepo = turnoRepo;
|
||||
this.scene = scene;
|
||||
this.undoRedoManager = undoRedoManager;
|
||||
|
||||
this.scene.onAdd(this::onAdd);
|
||||
this.scene.onRemove(this::onRemove);
|
||||
this.scene.onEdit(this::onEdit);
|
||||
this.scene.onUndo(this::onUndo);
|
||||
this.scene.onRedo(this::onRedo);
|
||||
|
||||
this.currentTurno = this.turnoRepo.getByFechaCajaTurno(LocalDate.now(), 1, 1);
|
||||
this.scene.setEgresos(this.egresoRepo.getByTurnoID(this.currentTurno.getId()));
|
||||
}
|
||||
|
||||
public void onTurnoChange(Turno turno) {
|
||||
this.currentTurno = turno;
|
||||
|
||||
undoRedoManager.clear();
|
||||
scene.setEgresos(egresoRepo.getByTurnoID(turno.getId()));
|
||||
}
|
||||
|
||||
private void onAdd() {
|
||||
log.info("Action: ADD");
|
||||
Egreso egreso = new Egreso(
|
||||
scene.getNro(),
|
||||
scene.getDescripcion(),
|
||||
scene.getValor(),
|
||||
scene.getTipo(),
|
||||
this.currentTurno.getId()
|
||||
);
|
||||
|
||||
undoRedoManager.execute(new AddEgresoCommand(egresoRepo, scene, egreso));
|
||||
}
|
||||
|
||||
private void onRemove(Egreso egreso) {
|
||||
log.info("Action: REMOVE");
|
||||
|
||||
if (egreso == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
undoRedoManager.execute(new RemoveEgresoCommand(egresoRepo, scene, egreso));
|
||||
}
|
||||
|
||||
private void onEdit(Egreso oldEgreso, Egreso newEgreso) {
|
||||
log.info("Action: EDIT");
|
||||
undoRedoManager.execute(new UpdateEgresoCommand(egresoRepo, scene, newEgreso, oldEgreso));
|
||||
}
|
||||
|
||||
private void onUndo() {
|
||||
log.info("Action: UNDO");
|
||||
undoRedoManager.undo();
|
||||
}
|
||||
|
||||
private void onRedo() {
|
||||
log.info("Action: REDO");
|
||||
undoRedoManager.redo();
|
||||
}
|
||||
}
|
||||
51
src/main/java/xyz/danielcortes/egresos/EgresoDAO.java
Executable file
51
src/main/java/xyz/danielcortes/egresos/EgresoDAO.java
Executable file
@@ -0,0 +1,51 @@
|
||||
package xyz.danielcortes.egresos;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import xyz.danielcortes.DAO;
|
||||
import xyz.danielcortes.DB;
|
||||
|
||||
public class EgresoDAO extends DAO<Egreso> {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(EgresoDAO.class);
|
||||
|
||||
public EgresoDAO(DB db) {
|
||||
super(db, "egreso", List.of("id", "nro", "descripcion", "valor", "tipo", "turno_id"));
|
||||
|
||||
}
|
||||
|
||||
public List<Egreso> findByTipo(TipoEgreso tipo) {
|
||||
return fetchMany("select * from egreso where tipo = ?", List.of(tipo));
|
||||
}
|
||||
|
||||
public List<Egreso> findByTurnoID(String turnoID) {
|
||||
return fetchMany("select * from egreso where turno_id = ?", List.of(turnoID));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Object> getColumnsValues(Egreso egreso) {
|
||||
return List.of(
|
||||
egreso.getId(),
|
||||
egreso.getNro(),
|
||||
egreso.getDescripcion(),
|
||||
egreso.getValor(),
|
||||
egreso.getTipo().toString(),
|
||||
egreso.getTurnoID()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Egreso mapToEntity(ResultSet rs) throws SQLException {
|
||||
return new Egreso(
|
||||
rs.getString("id"),
|
||||
rs.getString("nro"),
|
||||
rs.getString("descripcion"),
|
||||
rs.getInt("valor"),
|
||||
TipoEgreso.fromName(rs.getString("tipo")),
|
||||
rs.getString("turno_id")
|
||||
);
|
||||
}
|
||||
}
|
||||
71
src/main/java/xyz/danielcortes/egresos/EgresoRepo.java
Executable file
71
src/main/java/xyz/danielcortes/egresos/EgresoRepo.java
Executable file
@@ -0,0 +1,71 @@
|
||||
package xyz.danielcortes.egresos;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import xyz.danielcortes.DAO;
|
||||
import xyz.danielcortes.Repo;
|
||||
|
||||
public class EgresoRepo extends Repo<Egreso> {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(EgresoRepo.class);
|
||||
|
||||
private EgresoDAO dao;
|
||||
|
||||
public EgresoRepo(EgresoDAO dao) {
|
||||
super(dao);
|
||||
this.dao = dao;
|
||||
}
|
||||
|
||||
public List<Egreso> getByTipo(TipoEgreso tipo) {
|
||||
List<Egreso> egresos = new ArrayList<>();
|
||||
|
||||
for (Egreso egreso : toAdd.values()) {
|
||||
if (egreso.getTipo().equals(tipo)) {
|
||||
egresos.add(egreso);
|
||||
}
|
||||
}
|
||||
|
||||
for (Egreso egreso : toUpdate.values()) {
|
||||
if (egreso.getTipo().equals(tipo)) {
|
||||
egresos.add(egreso);
|
||||
}
|
||||
}
|
||||
|
||||
for(Egreso egreso : dao.findByTipo(tipo)){
|
||||
if(!egresos.contains(egreso) && !toRemove.containsKey(egreso.getId())){
|
||||
egresos.add(egreso);
|
||||
}
|
||||
}
|
||||
|
||||
return egresos;
|
||||
}
|
||||
|
||||
public List<Egreso> getByTurnoID(String turnoID) {
|
||||
List<Egreso> egresos = new ArrayList<>();
|
||||
|
||||
for (Egreso egreso : toAdd.values()) {
|
||||
if (egreso.getTurnoID().equals(turnoID)) {
|
||||
egresos.add(egreso);
|
||||
}
|
||||
}
|
||||
|
||||
for (Egreso egreso : toUpdate.values()) {
|
||||
if (egreso.getTurnoID().equals(turnoID)) {
|
||||
egresos.add(egreso);
|
||||
}
|
||||
}
|
||||
|
||||
for(Egreso egreso : dao.findByTurnoID(turnoID)){
|
||||
if(!egresos.contains(egreso) && !toRemove.containsKey(egreso.getId())){
|
||||
egresos.add(egreso);
|
||||
}
|
||||
}
|
||||
|
||||
return egresos;
|
||||
}
|
||||
}
|
||||
384
src/main/java/xyz/danielcortes/egresos/EgresoScene.java
Executable file
384
src/main/java/xyz/danielcortes/egresos/EgresoScene.java
Executable file
@@ -0,0 +1,384 @@
|
||||
package xyz.danielcortes.egresos;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Separator;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableColumn.CellEditEvent;
|
||||
import javafx.scene.control.TablePosition;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.control.TextFormatter;
|
||||
import javafx.scene.control.cell.ComboBoxTableCell;
|
||||
import javafx.scene.control.cell.PropertyValueFactory;
|
||||
import javafx.scene.control.cell.TextFieldTableCell;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.layout.ColumnConstraints;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.util.converter.IntegerStringConverter;
|
||||
import xyz.danielcortes.MathStringConverter;
|
||||
import xyz.danielcortes.listeners.AddListener;
|
||||
import xyz.danielcortes.listeners.EditListener;
|
||||
import xyz.danielcortes.listeners.RemoveListener;
|
||||
import xyz.danielcortes.listeners.SimpleListener;
|
||||
import xyz.danielcortes.menubar.AppMenu;
|
||||
import xyz.danielcortes.turno.TurnoToolbar;
|
||||
|
||||
public class EgresoScene {
|
||||
|
||||
private List<AddListener> addListeners;
|
||||
private List<RemoveListener<Egreso>> deleteListeners;
|
||||
private List<EditListener<Egreso>> editListeners;
|
||||
private List<SimpleListener> undoListeners;
|
||||
private List<SimpleListener> redoListeners;
|
||||
|
||||
private Scene scene;
|
||||
private TurnoToolbar turnoToolbar;
|
||||
private AppMenu menu;
|
||||
private TableView<Egreso> table;
|
||||
private ObservableList<Egreso> egresos;
|
||||
private ComboBox<TipoEgreso> tipoCombo;
|
||||
private TextField descripcionField;
|
||||
private TextField nroField;
|
||||
private TextField valorField;
|
||||
private Button addButton;
|
||||
private Button removeButton;
|
||||
|
||||
public EgresoScene(TurnoToolbar turnoToolbar, AppMenu menu) {
|
||||
this.turnoToolbar = turnoToolbar;
|
||||
this.menu = menu;
|
||||
addListeners = new LinkedList<>();
|
||||
deleteListeners = new LinkedList<>();
|
||||
editListeners = new LinkedList<>();
|
||||
undoListeners = new LinkedList<>();
|
||||
redoListeners = new LinkedList<>();
|
||||
|
||||
egresos = FXCollections.observableArrayList();
|
||||
scene = buildScene();
|
||||
|
||||
createListeners();
|
||||
setTraversalPolicy();
|
||||
}
|
||||
|
||||
private Scene buildScene() {
|
||||
var controls = createControls();
|
||||
var tableContainer = createTable();
|
||||
|
||||
var box = new VBox(
|
||||
menu.getMenuBar(),
|
||||
turnoToolbar.getToolbar(),
|
||||
new Separator(),
|
||||
controls,
|
||||
tableContainer
|
||||
);
|
||||
|
||||
VBox.setVgrow(tableContainer, Priority.ALWAYS);
|
||||
return new Scene(box);
|
||||
}
|
||||
|
||||
private VBox createTable() {
|
||||
table = new TableView<>();
|
||||
table.setEditable(true);
|
||||
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||
|
||||
var tipoColumn = new TableColumn<Egreso, TipoEgreso>("Tipo");
|
||||
var nroColumn = new TableColumn<Egreso, String>("N°");
|
||||
var descColumn = new TableColumn<Egreso, String>("Descripción");
|
||||
var valorColumn = new TableColumn<Egreso, Integer>("Valor");
|
||||
|
||||
tipoColumn.setCellValueFactory(new PropertyValueFactory<>("tipo"));
|
||||
tipoColumn.setCellFactory(ComboBoxTableCell.forTableColumn(TipoEgreso.values()));
|
||||
tipoColumn.setOnEditCommit((CellEditEvent<Egreso, TipoEgreso> event) -> {
|
||||
TablePosition<Egreso, TipoEgreso> pos = event.getTablePosition();
|
||||
TipoEgreso tipo = event.getNewValue();
|
||||
|
||||
Egreso oldEgreso = event.getTableView().getItems().get(pos.getRow());
|
||||
Egreso newEgreso = new Egreso(
|
||||
oldEgreso.getId(),
|
||||
oldEgreso.getNro(),
|
||||
oldEgreso.getDescripcion(),
|
||||
oldEgreso.getValor(),
|
||||
tipo,
|
||||
oldEgreso.getTurnoID()
|
||||
);
|
||||
event.getTableView().getItems().set(pos.getRow(), newEgreso);
|
||||
|
||||
this.notifyEditListeners(oldEgreso, newEgreso);
|
||||
});
|
||||
|
||||
nroColumn.setCellValueFactory(new PropertyValueFactory<>("nro"));
|
||||
nroColumn.setCellFactory(TextFieldTableCell.forTableColumn());
|
||||
nroColumn.setOnEditCommit((CellEditEvent<Egreso, String> event) -> {
|
||||
TablePosition<Egreso, String> pos = event.getTablePosition();
|
||||
String nro = event.getNewValue();
|
||||
|
||||
Egreso oldEgreso = event.getTableView().getItems().get(pos.getRow());
|
||||
Egreso newEgreso = new Egreso(
|
||||
oldEgreso.getId(),
|
||||
nro,
|
||||
oldEgreso.getDescripcion(),
|
||||
oldEgreso.getValor(),
|
||||
oldEgreso.getTipo(),
|
||||
oldEgreso.getTurnoID()
|
||||
);
|
||||
event.getTableView().getItems().set(pos.getRow(), newEgreso);
|
||||
|
||||
this.notifyEditListeners(oldEgreso, newEgreso);
|
||||
});
|
||||
|
||||
descColumn.setCellValueFactory(new PropertyValueFactory<>("descripcion"));
|
||||
descColumn.setCellFactory(TextFieldTableCell.forTableColumn());
|
||||
descColumn.setOnEditCommit((CellEditEvent<Egreso, String> event) -> {
|
||||
TablePosition<Egreso, String> pos = event.getTablePosition();
|
||||
String desc = event.getNewValue();
|
||||
|
||||
Egreso oldEgreso = event.getTableView().getItems().get(pos.getRow());
|
||||
Egreso newEgreso = new Egreso(
|
||||
oldEgreso.getId(),
|
||||
oldEgreso.getNro(),
|
||||
desc,
|
||||
oldEgreso.getValor(),
|
||||
oldEgreso.getTipo(),
|
||||
oldEgreso.getTurnoID()
|
||||
);
|
||||
event.getTableView().getItems().set(pos.getRow(), newEgreso);
|
||||
|
||||
this.notifyEditListeners(oldEgreso, newEgreso);
|
||||
});
|
||||
|
||||
valorColumn.setCellValueFactory(new PropertyValueFactory<>("valor"));
|
||||
valorColumn.setCellFactory(TextFieldTableCell.forTableColumn(new MathStringConverter()));
|
||||
valorColumn.setOnEditCommit((CellEditEvent<Egreso, Integer> event) -> {
|
||||
TablePosition<Egreso, Integer> pos = event.getTablePosition();
|
||||
int valor = event.getNewValue();
|
||||
|
||||
Egreso oldEgreso = event.getTableView().getItems().get(pos.getRow());
|
||||
Egreso newEgreso = new Egreso(
|
||||
oldEgreso.getId(),
|
||||
oldEgreso.getNro(),
|
||||
oldEgreso.getDescripcion(),
|
||||
valor,
|
||||
oldEgreso.getTipo(),
|
||||
oldEgreso.getTurnoID()
|
||||
);
|
||||
event.getTableView().getItems().set(pos.getRow(), newEgreso);
|
||||
|
||||
this.notifyEditListeners(oldEgreso, newEgreso);
|
||||
});
|
||||
|
||||
table.getColumns().add(tipoColumn);
|
||||
table.getColumns().add(nroColumn);
|
||||
table.getColumns().add(descColumn);
|
||||
table.getColumns().add(valorColumn);
|
||||
|
||||
table.setItems(egresos);
|
||||
|
||||
var box = new VBox(table);
|
||||
VBox.setVgrow(table, Priority.ALWAYS);
|
||||
return box;
|
||||
}
|
||||
|
||||
private GridPane createControls() {
|
||||
var grid = new GridPane();
|
||||
grid.setHgap(10);
|
||||
grid.setVgap(5);
|
||||
grid.setPadding(new Insets(10));
|
||||
|
||||
var colConstraintA = new ColumnConstraints();
|
||||
colConstraintA.setPercentWidth(22.5);
|
||||
grid.getColumnConstraints().add(colConstraintA);
|
||||
grid.getColumnConstraints().add(colConstraintA);
|
||||
grid.getColumnConstraints().add(colConstraintA);
|
||||
grid.getColumnConstraints().add(colConstraintA);
|
||||
var colConstraintB = new ColumnConstraints();
|
||||
colConstraintB.setPercentWidth(5);
|
||||
grid.getColumnConstraints().add(colConstraintB);
|
||||
grid.getColumnConstraints().add(colConstraintB);
|
||||
|
||||
tipoCombo = new ComboBox<>();
|
||||
tipoCombo.setItems(FXCollections.observableArrayList(TipoEgreso.values()));
|
||||
tipoCombo.setEditable(false);
|
||||
tipoCombo.setMaxWidth(Double.MAX_VALUE);
|
||||
tipoCombo.getSelectionModel().select(0);
|
||||
|
||||
nroField = new TextField();
|
||||
descripcionField = new TextField();
|
||||
valorField = new TextField();
|
||||
valorField.setTextFormatter(new TextFormatter<>(new MathStringConverter(), 0));
|
||||
|
||||
addButton = new Button("+");
|
||||
addButton.setMaxWidth(Double.MAX_VALUE);
|
||||
removeButton = new Button("-");
|
||||
removeButton.setMaxWidth(Double.MAX_VALUE);
|
||||
|
||||
grid.add(new Label("Tipo Ingreso"), 0, 0);
|
||||
grid.add(new Label("N°"), 1, 0);
|
||||
grid.add(new Label("Descripción"), 2, 0);
|
||||
grid.add(new Label("Valor"), 3, 0);
|
||||
grid.add(tipoCombo, 0, 1);
|
||||
grid.add(nroField, 1, 1);
|
||||
grid.add(descripcionField, 2, 1);
|
||||
grid.add(valorField, 3, 1);
|
||||
grid.add(addButton, 4, 1);
|
||||
grid.add(removeButton, 5, 1);
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
private void createListeners() {
|
||||
// Add listeners
|
||||
valorField.setOnAction(e -> notifyAddListeners());
|
||||
addButton.setOnAction(e -> notifyAddListeners());
|
||||
|
||||
// Delete listeners
|
||||
scene.addEventHandler(KeyEvent.KEY_RELEASED, e -> {
|
||||
if (e.getCode() == KeyCode.DELETE) {
|
||||
notifyRemoveListeners(getSelected());
|
||||
}
|
||||
});
|
||||
|
||||
removeButton.setOnAction(e -> notifyRemoveListeners(getSelected()));
|
||||
|
||||
// Undo Listeners
|
||||
scene.addEventHandler(KeyEvent.KEY_RELEASED, e -> {
|
||||
if (e.getCode() == KeyCode.Z && e.isControlDown() && !e.isShiftDown()) {
|
||||
notifyUndoListeners();
|
||||
}
|
||||
});
|
||||
|
||||
// Redo Listeners
|
||||
scene.addEventHandler(KeyEvent.KEY_RELEASED, e -> {
|
||||
if (e.getCode() == KeyCode.Z && e.isControlDown() && e.isShiftDown()) {
|
||||
notifyRedoListeners();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setTraversalPolicy() {
|
||||
tipoCombo.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
|
||||
if (event.getCode() == KeyCode.ENTER) {
|
||||
nroField.requestFocus();
|
||||
}
|
||||
});
|
||||
|
||||
nroField.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
|
||||
if (event.getCode() == KeyCode.ENTER) {
|
||||
descripcionField.requestFocus();
|
||||
}
|
||||
});
|
||||
|
||||
descripcionField.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
|
||||
if (event.getCode() == KeyCode.ENTER) {
|
||||
valorField.requestFocus();
|
||||
}
|
||||
});
|
||||
|
||||
valorField.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
|
||||
if (event.getCode() == KeyCode.ENTER) {
|
||||
tipoCombo.requestFocus();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void notifyEditListeners(Egreso oldEgreso, Egreso newEgreso) {
|
||||
editListeners.forEach(action -> action.run(oldEgreso, newEgreso));
|
||||
}
|
||||
|
||||
private void notifyAddListeners() {
|
||||
addListeners.forEach(AddListener::run);
|
||||
}
|
||||
|
||||
private void notifyRemoveListeners(Egreso egreso) {
|
||||
deleteListeners.forEach(action -> action.run(egreso));
|
||||
}
|
||||
|
||||
private void notifyUndoListeners() {
|
||||
undoListeners.forEach(SimpleListener::run);
|
||||
}
|
||||
|
||||
private void notifyRedoListeners() {
|
||||
redoListeners.forEach(SimpleListener::run);
|
||||
}
|
||||
|
||||
public Scene getScene() {
|
||||
return scene;
|
||||
}
|
||||
|
||||
public void setEgresos(List<Egreso> egresos) {
|
||||
this.egresos.clear();
|
||||
this.egresos.addAll(egresos);
|
||||
}
|
||||
|
||||
public void addEgresos(List<Egreso> egresos) {
|
||||
this.egresos.addAll(egresos);
|
||||
}
|
||||
|
||||
public void addEgreso(Egreso egreso) {
|
||||
this.egresos.add(egreso);
|
||||
}
|
||||
|
||||
public void updateEgreso(Egreso egreso) {
|
||||
this.egresos.set(egresos.indexOf(egreso), egreso);
|
||||
}
|
||||
|
||||
public void removeEgreso(Egreso egreso) {
|
||||
this.egresos.remove(egreso);
|
||||
}
|
||||
|
||||
public TipoEgreso getTipo() {
|
||||
return tipoCombo.getSelectionModel().getSelectedItem();
|
||||
}
|
||||
|
||||
public String getDescripcion() {
|
||||
return descripcionField.getText();
|
||||
}
|
||||
|
||||
public String getNro() {
|
||||
return nroField.getText();
|
||||
}
|
||||
|
||||
public int getValor() {
|
||||
int valor = 0;
|
||||
try {
|
||||
valor = Integer.parseInt(valorField.getText());
|
||||
} catch (NumberFormatException e) {
|
||||
System.out.println("Bad integer in valorField");
|
||||
}
|
||||
|
||||
return valor;
|
||||
}
|
||||
|
||||
public Egreso getSelected() {
|
||||
return table.getSelectionModel().getSelectedItem();
|
||||
}
|
||||
|
||||
public void onAdd(AddListener action) {
|
||||
addListeners.add(action);
|
||||
}
|
||||
|
||||
public void onRemove(RemoveListener<Egreso> action) {
|
||||
deleteListeners.add(action);
|
||||
}
|
||||
|
||||
public void onEdit(EditListener<Egreso> action) {
|
||||
editListeners.add(action);
|
||||
}
|
||||
|
||||
public void onUndo(SimpleListener action) {
|
||||
undoListeners.add(action);
|
||||
}
|
||||
|
||||
public void onRedo(SimpleListener action) {
|
||||
redoListeners.add(action);
|
||||
}
|
||||
}
|
||||
38
src/main/java/xyz/danielcortes/egresos/TipoEgreso.java
Executable file
38
src/main/java/xyz/danielcortes/egresos/TipoEgreso.java
Executable file
@@ -0,0 +1,38 @@
|
||||
package xyz.danielcortes.egresos;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public enum TipoEgreso {
|
||||
facturaMateriaPrima("Factura Materia Prima"),
|
||||
facturaGastosGenerales("Factura Gastos Generales"),
|
||||
boletaMateriaPrima("Boleta Materia Prima"),
|
||||
valeMateriaPrima("Vale Materia Prima"),
|
||||
boletaGastosGenerales("Boleta Gastos Generales"),
|
||||
valeGastosGenerales("Vale Gastos Generales"),
|
||||
guiaMateriaPrima("Guia Materia Prima"),
|
||||
anticipoArriendo("Anticipo Arriendo"),
|
||||
anticipoPersonal("Anticipo Personal"),
|
||||
pagoPartime("Pago Partime"),
|
||||
retirosGerencia("Retiros Gerencia"),
|
||||
otro("Otro");
|
||||
|
||||
private String name;
|
||||
|
||||
TipoEgreso (String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static TipoEgreso fromName(String name) {
|
||||
for (TipoEgreso tipo : TipoEgreso.values()) {
|
||||
if (Objects.equals(tipo.name, name)) {
|
||||
return tipo;
|
||||
}
|
||||
}
|
||||
return TipoEgreso.otro;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
34
src/main/java/xyz/danielcortes/egresos/commands/AddEgresoCommand.java
Executable file
34
src/main/java/xyz/danielcortes/egresos/commands/AddEgresoCommand.java
Executable file
@@ -0,0 +1,34 @@
|
||||
package xyz.danielcortes.egresos.commands;
|
||||
|
||||
import xyz.danielcortes.Command;
|
||||
import xyz.danielcortes.egresos.Egreso;
|
||||
import xyz.danielcortes.egresos.EgresoRepo;
|
||||
import xyz.danielcortes.egresos.EgresoScene;
|
||||
|
||||
public class AddEgresoCommand implements Command {
|
||||
private EgresoRepo repo;
|
||||
private EgresoScene scene;
|
||||
private Egreso egreso;
|
||||
|
||||
public AddEgresoCommand(EgresoRepo repo, EgresoScene scene, Egreso egreso) {
|
||||
this.repo = repo;
|
||||
this.scene = scene;
|
||||
this.egreso = egreso;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
repo.add(egreso);
|
||||
scene.addEgreso(egreso);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
repo.remove(egreso);
|
||||
scene.removeEgreso(egreso);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "AddEgresoCommand: " + egreso;
|
||||
}
|
||||
}
|
||||
35
src/main/java/xyz/danielcortes/egresos/commands/RemoveEgresoCommand.java
Executable file
35
src/main/java/xyz/danielcortes/egresos/commands/RemoveEgresoCommand.java
Executable file
@@ -0,0 +1,35 @@
|
||||
package xyz.danielcortes.egresos.commands;
|
||||
|
||||
import xyz.danielcortes.Command;
|
||||
import xyz.danielcortes.egresos.Egreso;
|
||||
import xyz.danielcortes.egresos.EgresoRepo;
|
||||
import xyz.danielcortes.egresos.EgresoScene;
|
||||
|
||||
public class RemoveEgresoCommand implements Command {
|
||||
private EgresoRepo repo;
|
||||
private EgresoScene scene;
|
||||
private Egreso egreso;
|
||||
|
||||
public RemoveEgresoCommand(EgresoRepo repo, EgresoScene scene, Egreso egreso) {
|
||||
this.repo = repo;
|
||||
this.scene = scene;
|
||||
this.egreso = egreso;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
repo.remove(egreso);
|
||||
scene.removeEgreso(egreso);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
repo.add(egreso);
|
||||
scene.addEgreso(egreso);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RemoveEgresoCommand: " + egreso;
|
||||
}
|
||||
}
|
||||
39
src/main/java/xyz/danielcortes/egresos/commands/UpdateEgresoCommand.java
Executable file
39
src/main/java/xyz/danielcortes/egresos/commands/UpdateEgresoCommand.java
Executable file
@@ -0,0 +1,39 @@
|
||||
package xyz.danielcortes.egresos.commands;
|
||||
|
||||
import xyz.danielcortes.Command;
|
||||
import xyz.danielcortes.egresos.Egreso;
|
||||
import xyz.danielcortes.egresos.EgresoRepo;
|
||||
import xyz.danielcortes.egresos.EgresoScene;
|
||||
|
||||
public class UpdateEgresoCommand implements Command {
|
||||
|
||||
private EgresoRepo repo;
|
||||
private EgresoScene scene;
|
||||
private Egreso newEgreso;
|
||||
private Egreso oldEgreso;
|
||||
|
||||
public UpdateEgresoCommand(EgresoRepo repo, EgresoScene scene, Egreso newEgreso, Egreso oldEgreso) {
|
||||
this.repo = repo;
|
||||
this.scene = scene;
|
||||
|
||||
this.newEgreso = newEgreso;
|
||||
this.oldEgreso = oldEgreso;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
repo.update(newEgreso);
|
||||
scene.updateEgreso(newEgreso);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
repo.update(oldEgreso);
|
||||
scene.updateEgreso(oldEgreso);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "UpdateEgresoCommand: " + oldEgreso + " -> " + newEgreso;
|
||||
}
|
||||
}
|
||||
70
src/main/java/xyz/danielcortes/ingresos/Ingreso.java
Executable file
70
src/main/java/xyz/danielcortes/ingresos/Ingreso.java
Executable file
@@ -0,0 +1,70 @@
|
||||
package xyz.danielcortes.ingresos;
|
||||
|
||||
import xyz.danielcortes.Entity;
|
||||
|
||||
public final class Ingreso extends Entity {
|
||||
private final int numero;
|
||||
private final int ingresoInicial;
|
||||
private final int ingresoFinal;
|
||||
private final int total;
|
||||
private final TipoIngreso tipo;
|
||||
private final String turnoID;
|
||||
|
||||
public Ingreso(int numero, int ingresoInicial, int ingresoFinal, int total,
|
||||
TipoIngreso tipo, String turnoID) {
|
||||
this.numero = numero;
|
||||
this.ingresoInicial = ingresoInicial;
|
||||
this.ingresoFinal = ingresoFinal;
|
||||
this.total = total;
|
||||
this.tipo = tipo;
|
||||
this.turnoID = turnoID;
|
||||
}
|
||||
|
||||
public Ingreso(String id, int numero, int ingresoInicial, int ingresoFinal, int total,
|
||||
TipoIngreso tipo, String turnoID) {
|
||||
super(id);
|
||||
this.numero = numero;
|
||||
this.ingresoInicial = ingresoInicial;
|
||||
this.ingresoFinal = ingresoFinal;
|
||||
this.total = total;
|
||||
this.tipo = tipo;
|
||||
this.turnoID = turnoID;
|
||||
}
|
||||
|
||||
public int getNumero() {
|
||||
return numero;
|
||||
}
|
||||
|
||||
public int getIngresoInicial() {
|
||||
return ingresoInicial;
|
||||
}
|
||||
|
||||
public int getIngresoFinal() {
|
||||
return ingresoFinal;
|
||||
}
|
||||
|
||||
public int getTotal() {
|
||||
return total;
|
||||
}
|
||||
|
||||
public TipoIngreso getTipo() {
|
||||
return tipo;
|
||||
}
|
||||
|
||||
public String getTurnoID() {
|
||||
return turnoID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Ingreso{" +
|
||||
"id='" + id + '\'' +
|
||||
", numero=" + numero +
|
||||
", ingresoInicial=" + ingresoInicial +
|
||||
", ingresoFinal=" + ingresoFinal +
|
||||
", total=" + total +
|
||||
", tipo=" + tipo +
|
||||
", turnoID='" + turnoID + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
55
src/main/java/xyz/danielcortes/ingresos/IngresoDAO.java
Executable file
55
src/main/java/xyz/danielcortes/ingresos/IngresoDAO.java
Executable file
@@ -0,0 +1,55 @@
|
||||
package xyz.danielcortes.ingresos;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import xyz.danielcortes.DAO;
|
||||
import xyz.danielcortes.DB;
|
||||
|
||||
public class IngresoDAO extends DAO<Ingreso> {
|
||||
|
||||
public IngresoDAO(DB db) {
|
||||
super(db, "ingreso",
|
||||
List.of("id", "nro", "ingreso_inicial", "ingreso_final", "total", "tipo", "turno_id"));
|
||||
}
|
||||
|
||||
public Ingreso findByTurnoIDAndTipo(String turnoID, TipoIngreso tipo) {
|
||||
return fetchSingle(
|
||||
"select * from ingreso where turno_id = ? and tipo = ?",
|
||||
List.of(turnoID, tipo.toString())
|
||||
);
|
||||
}
|
||||
|
||||
public List<Ingreso> findByTurnoID(String turnoID) {
|
||||
return fetchMany(
|
||||
"select * from ingreso where turno_id = ?",
|
||||
List.of(turnoID)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Object> getColumnsValues(Ingreso ingreso) {
|
||||
return List.of(
|
||||
ingreso.getId(),
|
||||
ingreso.getNumero(),
|
||||
ingreso.getIngresoInicial(),
|
||||
ingreso.getIngresoFinal(),
|
||||
ingreso.getTotal(),
|
||||
ingreso.getTipo(),
|
||||
ingreso.getTurnoID()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Ingreso mapToEntity(ResultSet rs) throws SQLException {
|
||||
return new Ingreso(
|
||||
rs.getString("id"),
|
||||
rs.getInt("nro"),
|
||||
rs.getInt("ingreso_inicial"),
|
||||
rs.getInt("ingreso_final"),
|
||||
rs.getInt("total"),
|
||||
TipoIngreso.fromName(rs.getString("tipo")),
|
||||
rs.getString("turno_id")
|
||||
);
|
||||
}
|
||||
}
|
||||
64
src/main/java/xyz/danielcortes/ingresos/IngresoRepo.java
Executable file
64
src/main/java/xyz/danielcortes/ingresos/IngresoRepo.java
Executable file
@@ -0,0 +1,64 @@
|
||||
package xyz.danielcortes.ingresos;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import xyz.danielcortes.DAO;
|
||||
import xyz.danielcortes.Repo;
|
||||
import xyz.danielcortes.egresos.Egreso;
|
||||
|
||||
public class IngresoRepo extends Repo<Ingreso> {
|
||||
private IngresoDAO dao;
|
||||
|
||||
public IngresoRepo(IngresoDAO dao) {
|
||||
super(dao);
|
||||
this.dao = dao;
|
||||
}
|
||||
|
||||
public List<Ingreso> getByTurnoIDAndTipo(String turnoID, TipoIngreso tipoIngreso) {
|
||||
List<Ingreso> ingresos = new ArrayList<>();
|
||||
|
||||
for (Ingreso ingreso : toAdd.values()) {
|
||||
if (ingreso.getTurnoID().equals(turnoID) && ingreso.getTipo().equals(tipoIngreso)) {
|
||||
ingresos.add(ingreso);
|
||||
}
|
||||
}
|
||||
|
||||
for (Ingreso ingreso : toUpdate.values()) {
|
||||
if (ingreso.getTurnoID().equals(turnoID) && ingreso.getTipo().equals(tipoIngreso)) {
|
||||
ingresos.add(ingreso);
|
||||
}
|
||||
}
|
||||
|
||||
for(Ingreso ingreso : dao.findByTurnoID(turnoID)){
|
||||
if(!ingresos.contains(ingreso) && !toRemove.containsKey(ingreso.getId())){
|
||||
ingresos.add(ingreso);
|
||||
}
|
||||
}
|
||||
|
||||
return ingresos;
|
||||
}
|
||||
|
||||
public List<Ingreso> getByTurnoID(String turnoID) {
|
||||
List<Ingreso> ingresos = new ArrayList<>();
|
||||
|
||||
for (Ingreso ingreso : toAdd.values()) {
|
||||
if (ingreso.getTurnoID().equals(turnoID)) {
|
||||
ingresos.add(ingreso);
|
||||
}
|
||||
}
|
||||
|
||||
for (Ingreso ingreso : toUpdate.values()) {
|
||||
if (ingreso.getTurnoID().equals(turnoID)) {
|
||||
ingresos.add(ingreso);
|
||||
}
|
||||
}
|
||||
|
||||
for(Ingreso ingreso : dao.findByTurnoID(turnoID)){
|
||||
if(!ingresos.contains(ingreso) && !toRemove.containsKey(ingreso.getId())){
|
||||
ingresos.add(ingreso);
|
||||
}
|
||||
}
|
||||
|
||||
return ingresos;
|
||||
}
|
||||
}
|
||||
365
src/main/java/xyz/danielcortes/ingresos/IngresoScene.java
Executable file
365
src/main/java/xyz/danielcortes/ingresos/IngresoScene.java
Executable file
@@ -0,0 +1,365 @@
|
||||
package xyz.danielcortes.ingresos;
|
||||
|
||||
import java.util.Objects;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.VPos;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Separator;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.Border;
|
||||
import javafx.scene.layout.BorderStroke;
|
||||
import javafx.scene.layout.BorderStrokeStyle;
|
||||
import javafx.scene.layout.BorderWidths;
|
||||
import javafx.scene.layout.ColumnConstraints;
|
||||
import javafx.scene.layout.CornerRadii;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.RowConstraints;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.paint.Paint;
|
||||
import javafx.scene.text.Font;
|
||||
import javafx.scene.text.FontWeight;
|
||||
import xyz.danielcortes.menubar.AppMenu;
|
||||
import xyz.danielcortes.turno.TurnoToolbar;
|
||||
|
||||
public class IngresoScene {
|
||||
|
||||
private Scene scene;
|
||||
private TurnoToolbar turnoToolbar;
|
||||
private AppMenu menu;
|
||||
|
||||
public IngresoScene(TurnoToolbar turnoToolbar, AppMenu menu) {
|
||||
this.turnoToolbar = turnoToolbar;
|
||||
this.menu = menu;
|
||||
scene = buildScene();
|
||||
scene.getStylesheets().add(
|
||||
Objects.requireNonNull(
|
||||
getClass().getClassLoader().getResource("app.css")
|
||||
).toString()
|
||||
);
|
||||
}
|
||||
|
||||
private Scene buildScene() {
|
||||
GridPane grid = new GridPane();
|
||||
grid.setHgap(10);
|
||||
grid.setVgap(5);
|
||||
grid.setPadding(new Insets(10));
|
||||
|
||||
GridPane boletasFiscales = buildBoletasFiscalesComponent();
|
||||
GridPane boletasManuales = buildBoletasManualesComponent();
|
||||
GridPane boletasExentas = buildBoletasExentasComponent();
|
||||
GridPane guias = buildGuiasComponent();
|
||||
GridPane facturas = buildFacturasComponent();
|
||||
GridPane totales = buildTotalesComponent();
|
||||
|
||||
grid.add(boletasFiscales, 0, 0);
|
||||
grid.add(boletasManuales, 1, 0);
|
||||
grid.add(boletasExentas, 2, 0);
|
||||
grid.add(guias, 0, 1);
|
||||
grid.add(facturas, 1, 1);
|
||||
grid.add(totales, 2, 1);
|
||||
|
||||
ColumnConstraints colConstraint = new ColumnConstraints();
|
||||
colConstraint.setPercentWidth(100 / 3);
|
||||
grid.getColumnConstraints().add(colConstraint);
|
||||
grid.getColumnConstraints().add(colConstraint);
|
||||
grid.getColumnConstraints().add(colConstraint);
|
||||
|
||||
VBox box = new VBox(menu.getMenuBar(), turnoToolbar.getToolbar(), new Separator(), grid);
|
||||
VBox.setVgrow(grid, Priority.ALWAYS);
|
||||
return new Scene(box);
|
||||
}
|
||||
|
||||
private GridPane buildBoletasFiscalesComponent() {
|
||||
var numeroXField = new TextField();
|
||||
var numeroZField = new TextField();
|
||||
var boletaInicialField = new TextField();
|
||||
var boletaFinalField = new TextField();
|
||||
var totalField = new TextField();
|
||||
|
||||
GridPane grid = new GridPane();
|
||||
grid.setHgap(10);
|
||||
grid.setVgap(2);
|
||||
grid.setPadding(new Insets(5));
|
||||
|
||||
Label title = new Label("Boletas Fiscales");
|
||||
title.setFont(Font.font("sans", FontWeight.BOLD, 13));
|
||||
grid.add(title, 0, 0);
|
||||
|
||||
grid.add(new Label("Numero X:"), 0, 1);
|
||||
grid.add(new Label("Numero Z:"), 1, 1);
|
||||
grid.add(numeroXField, 0, 2);
|
||||
grid.add(numeroZField, 1, 2);
|
||||
|
||||
grid.add(new Label("Boleta Inicial:"), 0, 3);
|
||||
grid.add(boletaInicialField, 0, 4, 2, 1);
|
||||
|
||||
grid.add(new Label("Boleta Final:"), 0, 5);
|
||||
grid.add(boletaFinalField, 0, 6, 2, 1);
|
||||
|
||||
grid.add(new Label("Total:"), 0, 7);
|
||||
grid.add(totalField, 0, 8, 2, 1);
|
||||
|
||||
ColumnConstraints constraints = new ColumnConstraints();
|
||||
constraints.setPercentWidth(100 / 2);
|
||||
grid.getColumnConstraints().add(constraints);
|
||||
grid.getColumnConstraints().add(constraints);
|
||||
|
||||
RowConstraints rowConstraints = new RowConstraints();
|
||||
rowConstraints.setMinHeight(30);
|
||||
rowConstraints.setValignment(VPos.TOP);
|
||||
grid.getRowConstraints().add(rowConstraints);
|
||||
|
||||
BorderStroke borderStroke = new BorderStroke(
|
||||
Color.rgb(200, 200, 200),
|
||||
BorderStrokeStyle.SOLID,
|
||||
CornerRadii.EMPTY,
|
||||
BorderWidths.DEFAULT
|
||||
);
|
||||
grid.setBorder(new Border(borderStroke));
|
||||
|
||||
grid.setMaxHeight(Double.MAX_VALUE);
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
private GridPane buildBoletasManualesComponent() {
|
||||
var boletaInicialField = new TextField();
|
||||
var boletaFinalField = new TextField();
|
||||
var totalField = new TextField();
|
||||
|
||||
GridPane grid = new GridPane();
|
||||
grid.setVgap(2);
|
||||
grid.setPadding(new Insets(5));
|
||||
|
||||
Label title = new Label("Boletas Manuales");
|
||||
title.setFont(Font.font("sans", FontWeight.BOLD, 13));
|
||||
grid.add(title, 0, 0);
|
||||
|
||||
grid.add(new Label("Boleta Inicial:"), 0, 1);
|
||||
grid.add(boletaInicialField, 0, 2);
|
||||
|
||||
grid.add(new Label("Boleta Final:"), 0, 3);
|
||||
grid.add(boletaFinalField, 0, 4);
|
||||
|
||||
grid.add(new Label("Total:"), 0, 5);
|
||||
grid.add(totalField, 0, 6);
|
||||
|
||||
ColumnConstraints constraints = new ColumnConstraints();
|
||||
constraints.setPercentWidth(100);
|
||||
grid.getColumnConstraints().add(constraints);
|
||||
|
||||
RowConstraints rowConstraints = new RowConstraints();
|
||||
rowConstraints.setMinHeight(30);
|
||||
rowConstraints.setValignment(VPos.TOP);
|
||||
grid.getRowConstraints().add(rowConstraints);
|
||||
|
||||
BorderStroke borderStroke = new BorderStroke(
|
||||
Color.rgb(200, 200, 200),
|
||||
BorderStrokeStyle.SOLID,
|
||||
CornerRadii.EMPTY,
|
||||
BorderWidths.DEFAULT
|
||||
);
|
||||
grid.setBorder(new Border(borderStroke));
|
||||
grid.setMaxHeight(Double.MAX_VALUE);
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
private GridPane buildBoletasExentasComponent() {
|
||||
var boletaInicialField = new TextField();
|
||||
var boletaFinalField = new TextField();
|
||||
var totalField = new TextField();
|
||||
|
||||
GridPane grid = new GridPane();
|
||||
grid.setVgap(2);
|
||||
grid.setPadding(new Insets(5));
|
||||
|
||||
Label title = new Label("Boletas Exentas");
|
||||
title.setFont(Font.font("sans", FontWeight.BOLD, 13));
|
||||
grid.add(title, 0, 0);
|
||||
|
||||
grid.add(new Label("Boleta Inicial:"), 0, 1);
|
||||
grid.add(boletaInicialField, 0, 2);
|
||||
|
||||
grid.add(new Label("Boleta Final:"), 0, 3);
|
||||
grid.add(boletaFinalField, 0, 4);
|
||||
|
||||
grid.add(new Label("Total:"), 0, 5);
|
||||
grid.add(totalField, 0, 6);
|
||||
|
||||
ColumnConstraints constraints = new ColumnConstraints();
|
||||
constraints.setPercentWidth(100);
|
||||
grid.getColumnConstraints().add(constraints);
|
||||
|
||||
RowConstraints rowConstraints = new RowConstraints();
|
||||
rowConstraints.setMinHeight(30);
|
||||
rowConstraints.setValignment(VPos.TOP);
|
||||
grid.getRowConstraints().add(rowConstraints);
|
||||
|
||||
BorderStroke borderStroke = new BorderStroke(
|
||||
Color.rgb(200, 200, 200),
|
||||
BorderStrokeStyle.SOLID,
|
||||
CornerRadii.EMPTY,
|
||||
BorderWidths.DEFAULT
|
||||
);
|
||||
grid.setBorder(new Border(borderStroke));
|
||||
grid.setMaxHeight(Double.MAX_VALUE);
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
private GridPane buildGuiasComponent() {
|
||||
var guiaInicialField = new TextField();
|
||||
var guiaFinalField = new TextField();
|
||||
var totalField = new TextField();
|
||||
|
||||
GridPane grid = new GridPane();
|
||||
grid.setVgap(2);
|
||||
grid.setPadding(new Insets(5));
|
||||
|
||||
Label title = new Label("Guias");
|
||||
title.setFont(Font.font("sans", FontWeight.BOLD, 13));
|
||||
grid.add(title, 0, 0);
|
||||
|
||||
grid.add(new Label("Guia Inicial:"), 0, 1);
|
||||
grid.add(guiaInicialField, 0, 2);
|
||||
|
||||
grid.add(new Label("Guia Final:"), 0, 3);
|
||||
grid.add(guiaFinalField, 0, 4);
|
||||
|
||||
grid.add(new Label("Total:"), 0, 5);
|
||||
grid.add(totalField, 0, 6);
|
||||
|
||||
ColumnConstraints constraints = new ColumnConstraints();
|
||||
constraints.setPercentWidth(100);
|
||||
grid.getColumnConstraints().add(constraints);
|
||||
|
||||
RowConstraints rowConstraints = new RowConstraints();
|
||||
rowConstraints.setMinHeight(30);
|
||||
rowConstraints.setValignment(VPos.TOP);
|
||||
grid.getRowConstraints().add(rowConstraints);
|
||||
|
||||
BorderStroke borderStroke = new BorderStroke(
|
||||
Color.rgb(200, 200, 200),
|
||||
BorderStrokeStyle.SOLID,
|
||||
CornerRadii.EMPTY,
|
||||
BorderWidths.DEFAULT
|
||||
);
|
||||
grid.setBorder(new Border(borderStroke));
|
||||
grid.setMaxHeight(Double.MAX_VALUE);
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
private GridPane buildFacturasComponent() {
|
||||
var facturaInicialField = new TextField();
|
||||
var facturaFinalField = new TextField();
|
||||
var totalField = new TextField();
|
||||
|
||||
GridPane grid = new GridPane();
|
||||
grid.setVgap(2);
|
||||
grid.setPadding(new Insets(5));
|
||||
|
||||
Label title = new Label("Facturas");
|
||||
title.setFont(Font.font("sans", FontWeight.BOLD, 13));
|
||||
grid.add(title, 0, 0);
|
||||
|
||||
grid.add(new Label("Factura Inicial:"), 0, 1);
|
||||
grid.add(facturaInicialField, 0, 2);
|
||||
|
||||
grid.add(new Label("Factura Final:"), 0, 3);
|
||||
grid.add(facturaFinalField, 0, 4);
|
||||
|
||||
grid.add(new Label("Total:"), 0, 5);
|
||||
grid.add(totalField, 0, 6);
|
||||
|
||||
ColumnConstraints constraints = new ColumnConstraints();
|
||||
constraints.setPercentWidth(100);
|
||||
grid.getColumnConstraints().add(constraints);
|
||||
|
||||
RowConstraints rowConstraints = new RowConstraints();
|
||||
rowConstraints.setMinHeight(30);
|
||||
rowConstraints.setValignment(VPos.TOP);
|
||||
grid.getRowConstraints().add(rowConstraints);
|
||||
|
||||
BorderStroke borderStroke = new BorderStroke(
|
||||
Color.rgb(200, 200, 200),
|
||||
BorderStrokeStyle.SOLID,
|
||||
CornerRadii.EMPTY,
|
||||
BorderWidths.DEFAULT
|
||||
);
|
||||
grid.setBorder(new Border(borderStroke));
|
||||
grid.setMaxHeight(Double.MAX_VALUE);
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
private GridPane buildTotalesComponent() {
|
||||
var boletasFiscalesField = new TextField();
|
||||
var boletasManualesField = new TextField();
|
||||
var boletasExentasField = new TextField();
|
||||
var guiasField = new TextField();
|
||||
var facturasField = new TextField();
|
||||
var totalField = new TextField();
|
||||
|
||||
boletasFiscalesField.setEditable(false);
|
||||
boletasManualesField.setEditable(false);
|
||||
boletasExentasField.setEditable(false);
|
||||
guiasField.setEditable(false);
|
||||
facturasField.setEditable(false);
|
||||
totalField.setEditable(false);
|
||||
|
||||
GridPane grid = new GridPane();
|
||||
grid.setVgap(2);
|
||||
grid.setPadding(new Insets(5));
|
||||
|
||||
Label title = new Label("Totales");
|
||||
title.setFont(Font.font("sans", FontWeight.BOLD, 13));
|
||||
grid.add(title, 0, 0);
|
||||
|
||||
grid.add(new Label("Boletas Fiscales:"), 0, 1);
|
||||
grid.add(boletasFiscalesField, 0, 2);
|
||||
|
||||
grid.add(new Label("Boletas Manuales:"), 0, 3);
|
||||
grid.add(boletasManualesField, 0, 4);
|
||||
|
||||
grid.add(new Label("Boletas Exentas:"), 0, 5);
|
||||
grid.add(boletasExentasField, 0, 6);
|
||||
|
||||
grid.add(new Label("Facturas:"), 0, 7);
|
||||
grid.add(facturasField, 0, 8);
|
||||
|
||||
grid.add(new Label("Guias:"), 0, 9);
|
||||
grid.add(guiasField, 0, 10);
|
||||
|
||||
grid.add(new Label("Total:"), 0, 11);
|
||||
grid.add(totalField, 0, 12);
|
||||
|
||||
ColumnConstraints colConstraints = new ColumnConstraints();
|
||||
colConstraints.setPercentWidth(100);
|
||||
grid.getColumnConstraints().add(colConstraints);
|
||||
|
||||
RowConstraints rowConstraints = new RowConstraints();
|
||||
rowConstraints.setMinHeight(30);
|
||||
rowConstraints.setValignment(VPos.TOP);
|
||||
grid.getRowConstraints().add(rowConstraints);
|
||||
|
||||
BorderStroke borderStroke = new BorderStroke(
|
||||
Color.rgb(200, 200, 200),
|
||||
BorderStrokeStyle.SOLID,
|
||||
CornerRadii.EMPTY,
|
||||
BorderWidths.DEFAULT
|
||||
);
|
||||
grid.setBorder(new Border(borderStroke));
|
||||
grid.setMaxHeight(Double.MAX_VALUE);
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
public Scene getScene() {
|
||||
return scene;
|
||||
}
|
||||
}
|
||||
31
src/main/java/xyz/danielcortes/ingresos/TipoIngreso.java
Executable file
31
src/main/java/xyz/danielcortes/ingresos/TipoIngreso.java
Executable file
@@ -0,0 +1,31 @@
|
||||
package xyz.danielcortes.ingresos;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public enum TipoIngreso {
|
||||
boletasFiscales("Boletas Fiscales"),
|
||||
boletasManuales("Boletas Manuales"),
|
||||
facturas("Facturas"),
|
||||
guias("Guías"),
|
||||
boletaExenta("Boleta Exenta");
|
||||
|
||||
private String name;
|
||||
|
||||
TipoIngreso(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static TipoIngreso fromName(String name) {
|
||||
for (TipoIngreso tipo : TipoIngreso.values()) {
|
||||
if (Objects.equals(tipo.name, name)) {
|
||||
return tipo;
|
||||
}
|
||||
}
|
||||
return TipoIngreso.boletaExenta;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
5
src/main/java/xyz/danielcortes/listeners/AddListener.java
Executable file
5
src/main/java/xyz/danielcortes/listeners/AddListener.java
Executable file
@@ -0,0 +1,5 @@
|
||||
package xyz.danielcortes.listeners;
|
||||
|
||||
public interface AddListener {
|
||||
void run();
|
||||
}
|
||||
5
src/main/java/xyz/danielcortes/listeners/EditListener.java
Executable file
5
src/main/java/xyz/danielcortes/listeners/EditListener.java
Executable file
@@ -0,0 +1,5 @@
|
||||
package xyz.danielcortes.listeners;
|
||||
|
||||
public interface EditListener<T> {
|
||||
void run(T oldT, T newT);
|
||||
}
|
||||
7
src/main/java/xyz/danielcortes/listeners/LoginListener.java
Executable file
7
src/main/java/xyz/danielcortes/listeners/LoginListener.java
Executable file
@@ -0,0 +1,7 @@
|
||||
package xyz.danielcortes.listeners;
|
||||
|
||||
import xyz.danielcortes.users.User;
|
||||
|
||||
public interface LoginListener {
|
||||
void login(User user);
|
||||
}
|
||||
5
src/main/java/xyz/danielcortes/listeners/ObjectChangeListener.java
Executable file
5
src/main/java/xyz/danielcortes/listeners/ObjectChangeListener.java
Executable file
@@ -0,0 +1,5 @@
|
||||
package xyz.danielcortes.listeners;
|
||||
|
||||
public interface ObjectChangeListener<T> {
|
||||
void run(T t);
|
||||
}
|
||||
5
src/main/java/xyz/danielcortes/listeners/RemoveListener.java
Executable file
5
src/main/java/xyz/danielcortes/listeners/RemoveListener.java
Executable file
@@ -0,0 +1,5 @@
|
||||
package xyz.danielcortes.listeners;
|
||||
|
||||
public interface RemoveListener<T> {
|
||||
void run(T t);
|
||||
}
|
||||
5
src/main/java/xyz/danielcortes/listeners/SimpleListener.java
Executable file
5
src/main/java/xyz/danielcortes/listeners/SimpleListener.java
Executable file
@@ -0,0 +1,5 @@
|
||||
package xyz.danielcortes.listeners;
|
||||
|
||||
public interface SimpleListener {
|
||||
void run();
|
||||
}
|
||||
87
src/main/java/xyz/danielcortes/menubar/AppMenu.java
Executable file
87
src/main/java/xyz/danielcortes/menubar/AppMenu.java
Executable file
@@ -0,0 +1,87 @@
|
||||
package xyz.danielcortes.menubar;
|
||||
|
||||
import java.util.List;
|
||||
import javafx.event.EventType;
|
||||
import javafx.scene.control.Menu;
|
||||
import javafx.scene.control.MenuBar;
|
||||
import javafx.scene.control.MenuItem;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import xyz.danielcortes.listeners.SimpleListener;
|
||||
|
||||
public class AppMenu {
|
||||
|
||||
private MenuBar menuBar;
|
||||
|
||||
private MenuItem ingresosItem;
|
||||
private MenuItem egresosItem;
|
||||
private MenuItem arqueoItem;
|
||||
|
||||
private MenuItem informeEgresosItem;
|
||||
private MenuItem informeArqueoItem;
|
||||
private MenuItem informeLibroItem;
|
||||
private MenuItem informeEstadoResultadoItem;
|
||||
|
||||
private MenuItem configUsuarioItem;
|
||||
|
||||
public AppMenu() {
|
||||
this.menuBar = buildMenu();
|
||||
}
|
||||
|
||||
private MenuBar buildMenu() {
|
||||
var cajaMenu = new Menu("Caja");
|
||||
ingresosItem = new MenuItem("Ingresos");
|
||||
egresosItem = new MenuItem("Egresos");
|
||||
arqueoItem = new MenuItem("Arqueo");
|
||||
cajaMenu.getItems().add(ingresosItem);
|
||||
cajaMenu.getItems().add(egresosItem);
|
||||
cajaMenu.getItems().add(arqueoItem);
|
||||
|
||||
var informesMenu = new Menu("Informes");
|
||||
informeEgresosItem = new MenuItem("Resumen Egresos");
|
||||
informeArqueoItem = new MenuItem("Resumen Arqueo");
|
||||
informeLibroItem = new MenuItem("Libro de Ventas");
|
||||
informeEstadoResultadoItem = new MenuItem("Estado Resultado");
|
||||
informesMenu.getItems().add(informeEgresosItem);
|
||||
informesMenu.getItems().add(informeArqueoItem);
|
||||
informesMenu.getItems().add(informeLibroItem);
|
||||
informesMenu.getItems().add(informeEstadoResultadoItem);
|
||||
|
||||
var configMenu = new Menu("Configuracion");
|
||||
configUsuarioItem = new MenuItem("Usuarios");
|
||||
configMenu.getItems().add(configUsuarioItem);
|
||||
|
||||
var bar = new MenuBar();
|
||||
bar.getMenus().add(cajaMenu);
|
||||
bar.getMenus().add(informesMenu);
|
||||
bar.getMenus().add(configMenu);
|
||||
|
||||
return bar;
|
||||
}
|
||||
|
||||
public MenuBar getMenuBar() { return menuBar; }
|
||||
|
||||
public void addIngresosListener(SimpleListener listener) {
|
||||
ingresosItem.addEventHandler(MouseEvent.MOUSE_CLICKED, e -> listener.run());
|
||||
}
|
||||
public void addEgresosListener(SimpleListener listener) {
|
||||
egresosItem.addEventHandler(MouseEvent.MOUSE_CLICKED, e -> listener.run());
|
||||
}
|
||||
public void addArqueoListener(SimpleListener listener) {
|
||||
arqueoItem.addEventHandler(MouseEvent.MOUSE_CLICKED, e -> listener.run());
|
||||
}
|
||||
public void addInformeEgresosListener(SimpleListener listener) {
|
||||
informeEgresosItem.addEventHandler(MouseEvent.MOUSE_CLICKED, e -> listener.run());
|
||||
}
|
||||
public void addInformeArqueoItemListener(SimpleListener listener) {
|
||||
informeArqueoItem.addEventHandler(MouseEvent.MOUSE_CLICKED, e -> listener.run());
|
||||
}
|
||||
public void addInformeLibroListener(SimpleListener listener) {
|
||||
informeLibroItem.addEventHandler(MouseEvent.MOUSE_CLICKED, e -> listener.run());
|
||||
}
|
||||
public void addInformeEstadoResultadoListener(SimpleListener listener) {
|
||||
informeEstadoResultadoItem.addEventHandler(MouseEvent.MOUSE_CLICKED, e -> listener.run());
|
||||
}
|
||||
public void addConfigUsuarioListener(SimpleListener listener) {
|
||||
configUsuarioItem.addEventHandler(MouseEvent.MOUSE_CLICKED, e -> listener.run());
|
||||
}
|
||||
}
|
||||
63
src/main/java/xyz/danielcortes/turno/Turno.java
Executable file
63
src/main/java/xyz/danielcortes/turno/Turno.java
Executable file
@@ -0,0 +1,63 @@
|
||||
package xyz.danielcortes.turno;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
import xyz.danielcortes.Entity;
|
||||
import xyz.danielcortes.egresos.Egreso;
|
||||
|
||||
public final class Turno extends Entity {
|
||||
|
||||
private final LocalDate fecha;
|
||||
private final Integer numeroCaja;
|
||||
private final Integer numeroTurno;
|
||||
private final Integer fondo;
|
||||
|
||||
public Turno(String id, LocalDate fecha, Integer numeroCaja, Integer numeroTurno,
|
||||
Integer fondo) {
|
||||
super(id);
|
||||
this.fecha = fecha;
|
||||
this.numeroCaja = numeroCaja;
|
||||
this.numeroTurno = numeroTurno;
|
||||
this.fondo = fondo;
|
||||
}
|
||||
|
||||
public Turno(LocalDate fecha, Integer numeroCaja, Integer numeroTurno, Integer fondo) {
|
||||
super();
|
||||
this.fecha = fecha;
|
||||
this.numeroCaja = numeroCaja;
|
||||
this.numeroTurno = numeroTurno;
|
||||
this.fondo = fondo;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public LocalDate getFecha() {
|
||||
return fecha;
|
||||
}
|
||||
|
||||
public Integer getNumeroCaja() {
|
||||
return numeroCaja;
|
||||
}
|
||||
|
||||
public Integer getNumeroTurno() {
|
||||
return numeroTurno;
|
||||
}
|
||||
|
||||
public Integer getFondo() {
|
||||
return fondo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Turno{" +
|
||||
"id='" + id + '\'' +
|
||||
", fecha=" + fecha +
|
||||
", numeroCaja=" + numeroCaja +
|
||||
", numeroTurno=" + numeroTurno +
|
||||
", fondo=" + fondo +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
48
src/main/java/xyz/danielcortes/turno/TurnoDAO.java
Executable file
48
src/main/java/xyz/danielcortes/turno/TurnoDAO.java
Executable file
@@ -0,0 +1,48 @@
|
||||
package xyz.danielcortes.turno;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import xyz.danielcortes.DAO;
|
||||
import xyz.danielcortes.DB;
|
||||
|
||||
public class TurnoDAO extends DAO<Turno> {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(TurnoDAO.class);
|
||||
|
||||
public TurnoDAO(DB db) {
|
||||
super(db, "turno", List.of("id", "fecha", "numero_caja", "numero_turno", "fondo"));
|
||||
}
|
||||
|
||||
public Turno findByFechaCajaTurno(LocalDate fecha, int numeroCaja, int numeroTurno) {
|
||||
return fetchSingle(
|
||||
"select * from turno where fecha = ? and numero_caja = ? and numero_turno = ?",
|
||||
List.of(fecha, numeroCaja, numeroTurno)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Object> getColumnsValues(Turno turno) {
|
||||
return List.of(
|
||||
turno.getId(),
|
||||
turno.getFecha(),
|
||||
turno.getNumeroCaja(),
|
||||
turno.getNumeroTurno(),
|
||||
turno.getFondo()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Turno mapToEntity(ResultSet rs) throws SQLException {
|
||||
return new Turno(
|
||||
rs.getString("id"),
|
||||
rs.getObject("fecha", LocalDate.class),
|
||||
rs.getInt("numero_caja"),
|
||||
rs.getInt("numero_turno"),
|
||||
rs.getInt("fondo")
|
||||
);
|
||||
}
|
||||
}
|
||||
46
src/main/java/xyz/danielcortes/turno/TurnoRepo.java
Executable file
46
src/main/java/xyz/danielcortes/turno/TurnoRepo.java
Executable file
@@ -0,0 +1,46 @@
|
||||
package xyz.danielcortes.turno;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import xyz.danielcortes.Repo;
|
||||
|
||||
public class TurnoRepo extends Repo<Turno> {
|
||||
|
||||
private TurnoDAO dao;
|
||||
|
||||
public TurnoRepo(TurnoDAO dao) {
|
||||
super(dao);
|
||||
this.dao = dao;
|
||||
}
|
||||
|
||||
public Turno getByFechaCajaTurno(LocalDate fecha, int numeroCaja, int numeroTurno) {
|
||||
for (Turno turno : toAdd.values()) {
|
||||
if (turno.getFecha().equals(fecha) &&
|
||||
turno.getNumeroCaja() == numeroCaja &&
|
||||
turno.getNumeroTurno() == numeroTurno) {
|
||||
return turno;
|
||||
}
|
||||
}
|
||||
|
||||
for (Turno turno : toUpdate.values()) {
|
||||
if (turno.getFecha().equals(fecha) &&
|
||||
turno.getNumeroCaja() == numeroCaja &&
|
||||
turno.getNumeroTurno() == numeroTurno) {
|
||||
return turno;
|
||||
}
|
||||
}
|
||||
|
||||
var turno = dao.findByFechaCajaTurno(fecha, numeroCaja, numeroTurno);
|
||||
|
||||
if(turno == null) {
|
||||
turno = new Turno(fecha,numeroCaja, numeroTurno, 0);
|
||||
toAdd.put(turno.getId(), turno);
|
||||
return turno;
|
||||
}
|
||||
|
||||
if (!toRemove.containsKey(turno.getId())) {
|
||||
return turno;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
99
src/main/java/xyz/danielcortes/turno/TurnoToolbar.java
Executable file
99
src/main/java/xyz/danielcortes/turno/TurnoToolbar.java
Executable file
@@ -0,0 +1,99 @@
|
||||
package xyz.danielcortes.turno;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.VPos;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.DatePicker;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Spinner;
|
||||
import javafx.scene.control.SpinnerValueFactory.IntegerSpinnerValueFactory;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Priority;
|
||||
import xyz.danielcortes.listeners.SimpleListener;
|
||||
|
||||
public class TurnoToolbar {
|
||||
|
||||
private GridPane toolbar;
|
||||
|
||||
private DatePicker fecha;
|
||||
private Spinner<Integer> caja;
|
||||
private Spinner<Integer> turno;
|
||||
private Button guardarButton;
|
||||
|
||||
public TurnoToolbar() {
|
||||
toolbar = buildToolbar();
|
||||
}
|
||||
|
||||
private GridPane buildToolbar() {
|
||||
guardarButton = new Button("Guardar");
|
||||
guardarButton.setPrefWidth(100);
|
||||
|
||||
fecha = new DatePicker();
|
||||
caja = new Spinner<>();
|
||||
turno = new Spinner<>();
|
||||
|
||||
fecha.setValue(LocalDate.now());
|
||||
caja.setValueFactory(new IntegerSpinnerValueFactory(1, 9));
|
||||
turno.setValueFactory(new IntegerSpinnerValueFactory(1, 9));
|
||||
|
||||
var grid = new GridPane();
|
||||
grid.setPadding(new Insets(10, 10, 10, 10));
|
||||
grid.setHgap(10);
|
||||
grid.setVgap(5);
|
||||
|
||||
var spacer = new HBox();
|
||||
grid.add(new Label("Dia:"), 0, 0);
|
||||
grid.add(new Label("Caja:"), 1, 0);
|
||||
grid.add(new Label("Turno:"), 2, 0);
|
||||
grid.add(fecha, 0, 1);
|
||||
grid.add(caja, 1, 1);
|
||||
grid.add(turno, 2, 1);
|
||||
grid.add(spacer, 3, 1);
|
||||
grid.add(guardarButton, 4, 1);
|
||||
|
||||
GridPane.setHgrow(spacer, Priority.ALWAYS);
|
||||
GridPane.setValignment(guardarButton, VPos.TOP);
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
public GridPane getToolbar() {
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
public int getCaja() {
|
||||
return caja.getValue();
|
||||
}
|
||||
|
||||
public int getTurno() {
|
||||
return turno.getValue();
|
||||
}
|
||||
|
||||
public LocalDate getFecha() {
|
||||
return fecha.getValue();
|
||||
}
|
||||
|
||||
public void onGuardar(SimpleListener listener) {
|
||||
guardarButton.setOnAction(e -> listener.run());
|
||||
}
|
||||
|
||||
public void onFechaChange(SimpleListener listener) {
|
||||
fecha.valueProperty().addListener((observable, oldValue, newValue) -> {
|
||||
listener.run();
|
||||
});
|
||||
}
|
||||
|
||||
public void onCajaChange(SimpleListener listener) {
|
||||
caja.valueProperty().addListener((observable, oldValue, newValue) -> {
|
||||
listener.run();
|
||||
});
|
||||
}
|
||||
|
||||
public void onTurnoChange(SimpleListener listener) {
|
||||
turno.valueProperty().addListener((observable, oldValue, newValue) -> {
|
||||
listener.run();
|
||||
});
|
||||
}
|
||||
}
|
||||
54
src/main/java/xyz/danielcortes/turno/TurnoToolbarController.java
Executable file
54
src/main/java/xyz/danielcortes/turno/TurnoToolbarController.java
Executable file
@@ -0,0 +1,54 @@
|
||||
package xyz.danielcortes.turno;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import xyz.danielcortes.listeners.ObjectChangeListener;
|
||||
import xyz.danielcortes.listeners.SimpleListener;
|
||||
|
||||
public class TurnoToolbarController {
|
||||
|
||||
private TurnoToolbar toolbar;
|
||||
|
||||
private TurnoRepo repo;
|
||||
private List<SimpleListener> saveListeners;
|
||||
private List<ObjectChangeListener<Turno>> turnoChangeListeners;
|
||||
|
||||
public TurnoToolbarController(TurnoToolbar toolbar, TurnoRepo turnoRepo) {
|
||||
this.toolbar = toolbar;
|
||||
this.repo = turnoRepo;
|
||||
|
||||
this.saveListeners = new LinkedList<>();
|
||||
this.turnoChangeListeners = new LinkedList<>();
|
||||
|
||||
setupListeners();
|
||||
}
|
||||
|
||||
private void setupListeners() {
|
||||
this.toolbar.onGuardar(this::notifySaveListeners);
|
||||
this.toolbar.onFechaChange(this::loadNewTurno);
|
||||
this.toolbar.onCajaChange(this::loadNewTurno);
|
||||
this.toolbar.onTurnoChange(this::loadNewTurno);
|
||||
}
|
||||
|
||||
private void loadNewTurno() {
|
||||
var turno = repo.getByFechaCajaTurno(toolbar.getFecha(), toolbar.getCaja(), toolbar.getTurno());
|
||||
notifyTurnoChangeListeners(turno);
|
||||
}
|
||||
|
||||
public void addTurnoChangeListener(ObjectChangeListener<Turno> listener) {
|
||||
turnoChangeListeners.add(listener);
|
||||
}
|
||||
|
||||
public void addSaveListener(SimpleListener listener) {
|
||||
saveListeners.add(listener);
|
||||
}
|
||||
|
||||
public void notifySaveListeners() {
|
||||
saveListeners.forEach(SimpleListener::run);
|
||||
}
|
||||
|
||||
public void notifyTurnoChangeListeners(Turno turno) {
|
||||
turnoChangeListeners.forEach(listener -> listener.run(turno));
|
||||
}
|
||||
|
||||
}
|
||||
69
src/main/java/xyz/danielcortes/users/LoginController.java
Executable file
69
src/main/java/xyz/danielcortes/users/LoginController.java
Executable file
@@ -0,0 +1,69 @@
|
||||
package xyz.danielcortes.users;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Alert.AlertType;
|
||||
import javafx.stage.StageStyle;
|
||||
import xyz.danielcortes.listeners.LoginListener;
|
||||
|
||||
public class LoginController {
|
||||
|
||||
private UserRepo userRepo;
|
||||
private LoginScene loginScene;
|
||||
|
||||
private List<LoginListener> loginListeners;
|
||||
|
||||
public LoginController(LoginScene loginScene, UserRepo userRepo) {
|
||||
this.loginListeners = new LinkedList<>();
|
||||
this.loginScene = loginScene;
|
||||
this.userRepo = userRepo;
|
||||
this.loginScene.onLogin(this::onLogin);
|
||||
}
|
||||
|
||||
public void addLoginListener(LoginListener loginListener) {
|
||||
loginListeners.add(loginListener);
|
||||
}
|
||||
|
||||
public void onLogin() {
|
||||
Alert alert = new Alert(AlertType.ERROR);
|
||||
alert.initStyle(StageStyle.DECORATED);
|
||||
alert.setHeaderText(null);
|
||||
alert.setTitle("Error");
|
||||
alert.setContentText("El usuario o contraseña no son correctos");
|
||||
|
||||
if (loginScene.getUsername().length() <= 0) {
|
||||
loginScene.clearError();
|
||||
loginScene.inputUsernameError();
|
||||
loginScene.focusUsername();
|
||||
return;
|
||||
}
|
||||
|
||||
if (loginScene.getPassword().length <= 0) {
|
||||
loginScene.clearError();
|
||||
loginScene.inputPasswordError();
|
||||
loginScene.focusPassword();
|
||||
return;
|
||||
}
|
||||
|
||||
User user = userRepo.getByNombre(loginScene.getUsername());
|
||||
if (user == null) {
|
||||
alert.showAndWait();
|
||||
loginScene.focusUsername();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user.comparePassword(loginScene.getPassword())) {
|
||||
alert.showAndWait();
|
||||
loginScene.focusPassword();
|
||||
return;
|
||||
}
|
||||
|
||||
notifyLoginListeners(user);
|
||||
}
|
||||
|
||||
private void notifyLoginListeners(User user) {
|
||||
loginListeners.forEach(l -> l.login(user));
|
||||
}
|
||||
}
|
||||
110
src/main/java/xyz/danielcortes/users/LoginScene.java
Executable file
110
src/main/java/xyz/danielcortes/users/LoginScene.java
Executable file
@@ -0,0 +1,110 @@
|
||||
package xyz.danielcortes.users;
|
||||
|
||||
import java.util.Objects;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.PasswordField;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.text.Font;
|
||||
import javafx.scene.text.FontWeight;
|
||||
import javafx.scene.text.Text;
|
||||
import xyz.danielcortes.listeners.SimpleListener;
|
||||
|
||||
public class LoginScene {
|
||||
|
||||
private Scene scene;
|
||||
private TextField usernameField;
|
||||
private PasswordField passwordField;
|
||||
private Button loginButton;
|
||||
|
||||
public LoginScene() {
|
||||
scene = buildScene();
|
||||
scene.getStylesheets().add(
|
||||
Objects.requireNonNull(
|
||||
getClass().getClassLoader().getResource("app.css")
|
||||
).toString()
|
||||
);
|
||||
}
|
||||
|
||||
public Scene buildScene() {
|
||||
GridPane grid = new GridPane();
|
||||
grid.setAlignment(Pos.CENTER);
|
||||
grid.setHgap(10);
|
||||
grid.setVgap(10);
|
||||
|
||||
var title = new Text("Bienvenido");
|
||||
title.setFont(Font.font("Raleway", FontWeight.NORMAL, 20));
|
||||
grid.add(title, 0, 0, 2, 1);
|
||||
|
||||
var username = new Label("Usuario:");
|
||||
var usernameBox = new VBox();
|
||||
usernameBox.getChildren().add(username);
|
||||
usernameBox.setAlignment(Pos.BASELINE_RIGHT);
|
||||
grid.add(usernameBox, 0, 1);
|
||||
|
||||
usernameField = new TextField();
|
||||
grid.add(usernameField, 1, 1);
|
||||
|
||||
var password = new Label("Password:");
|
||||
var passwordBox = new VBox();
|
||||
passwordBox.getChildren().add(password);
|
||||
passwordBox.setAlignment(Pos.BASELINE_RIGHT);
|
||||
grid.add(password, 0, 2);
|
||||
|
||||
passwordField = new PasswordField();
|
||||
grid.add(passwordField, 1, 2);
|
||||
|
||||
loginButton = new Button("Log in");
|
||||
var buttonHBox = new HBox(10);
|
||||
buttonHBox.setAlignment(Pos.BASELINE_RIGHT);
|
||||
buttonHBox.getChildren().add(loginButton);
|
||||
grid.add(buttonHBox, 1, 4);
|
||||
|
||||
var action = new Text();
|
||||
grid.add(action, 1, 6);
|
||||
|
||||
return new Scene(grid, 400, 300);
|
||||
}
|
||||
|
||||
public void onLogin(SimpleListener action) {
|
||||
loginButton.setOnAction(e -> action.run());
|
||||
}
|
||||
|
||||
public Scene getScene() {
|
||||
return scene;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return usernameField.getText();
|
||||
}
|
||||
|
||||
public char[] getPassword() {
|
||||
return passwordField.getText().toCharArray();
|
||||
}
|
||||
|
||||
public void focusUsername() {
|
||||
usernameField.requestFocus();
|
||||
}
|
||||
|
||||
public void focusPassword() {
|
||||
passwordField.requestFocus();
|
||||
}
|
||||
|
||||
public void inputUsernameError(){
|
||||
usernameField.getStyleClass().add("error");
|
||||
}
|
||||
|
||||
public void inputPasswordError() {
|
||||
passwordField.getStyleClass().add("error");
|
||||
}
|
||||
|
||||
public void clearError() {
|
||||
usernameField.getStyleClass().remove("error");
|
||||
passwordField.getStyleClass().remove("error");
|
||||
}
|
||||
}
|
||||
73
src/main/java/xyz/danielcortes/users/Passwords.java
Executable file
73
src/main/java/xyz/danielcortes/users/Passwords.java
Executable file
@@ -0,0 +1,73 @@
|
||||
package xyz.danielcortes.users;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
|
||||
/**
|
||||
* Clase encargada de crear y comparar contraseñas de forma segura
|
||||
*/
|
||||
public class Passwords {
|
||||
|
||||
private static final Random RANDOM = new SecureRandom();
|
||||
private static final int ITERATIONS = 10000;
|
||||
private static final int KEY_LENGHT = 256;
|
||||
|
||||
private Passwords() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Genera aleatoriamente un <code>byte[]</code> de tamaño 16
|
||||
*
|
||||
* @return El <code>byte[]</code> generados
|
||||
*/
|
||||
public static byte[] getNextSalt() {
|
||||
byte[] salt = new byte[16];
|
||||
RANDOM.nextBytes(salt);
|
||||
return salt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compara 2 contraseñas, la primera sin hashear aun y la segunda ya hasheada
|
||||
*
|
||||
* @param password <code>char[]</code> que contiene la contraseña sin hashear aun
|
||||
* @param salt <code>byte[]</code> que contiene la sal con la que juntar la contraseña al momento de hashearla
|
||||
* @param expectedHash <code>byte[]</code> con una contraseña ya hasheada con la que comprar
|
||||
* @return un boleano indicando que las contraseñas son iguales o no
|
||||
*/
|
||||
public static boolean isExpectedPassword(char[] password, byte[] salt, byte[] expectedHash) {
|
||||
byte[] pwdHash = hash(password, salt);
|
||||
Arrays.fill(password, Character.MIN_VALUE);
|
||||
if (pwdHash.length != expectedHash.length)
|
||||
return false;
|
||||
for (int i = 0; i < pwdHash.length; i++) {
|
||||
if (pwdHash[i] != expectedHash[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashea una contraseña.
|
||||
*
|
||||
* @param password <code>char[]</code> con la contraseña a hashear
|
||||
* @param salt <code>byte[]</code> con la salt que se le aplicara a la contraseña
|
||||
* @return <code>byte[]</code> con la contraseña hasheada
|
||||
*/
|
||||
public static byte[] hash(char[] password, byte[] salt) {
|
||||
PBEKeySpec spec = new PBEKeySpec(password, salt, ITERATIONS, KEY_LENGHT);
|
||||
Arrays.fill(password, Character.MIN_VALUE);
|
||||
try {
|
||||
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
|
||||
return skf.generateSecret(spec).getEncoded();
|
||||
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
|
||||
throw new AssertionError("Error while hashing a password: " + e.getMessage(), e);
|
||||
} finally {
|
||||
spec.clearPassword();
|
||||
}
|
||||
}
|
||||
}
|
||||
75
src/main/java/xyz/danielcortes/users/User.java
Executable file
75
src/main/java/xyz/danielcortes/users/User.java
Executable file
@@ -0,0 +1,75 @@
|
||||
package xyz.danielcortes.users;
|
||||
|
||||
import java.util.UUID;
|
||||
import xyz.danielcortes.Entity;
|
||||
import xyz.danielcortes.egresos.Egreso;
|
||||
|
||||
public final class User extends Entity {
|
||||
|
||||
private final String nombre;
|
||||
private final byte[] password;
|
||||
private final byte[] salt;
|
||||
|
||||
public User(String nombre, char[] password) {
|
||||
super();
|
||||
this.nombre = nombre;
|
||||
this.salt = Passwords.getNextSalt();
|
||||
this.password = Passwords.hash(password, salt);
|
||||
}
|
||||
|
||||
public User(String id, String nombre, byte[] password, byte[] salt) {
|
||||
super(id);
|
||||
this.nombre = nombre;
|
||||
this.password = password;
|
||||
this.salt = salt;
|
||||
}
|
||||
|
||||
public final String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public final String getNombre() {
|
||||
return nombre;
|
||||
}
|
||||
|
||||
public final byte[] getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public final byte[] getSalt() {
|
||||
return salt;
|
||||
}
|
||||
|
||||
public final boolean comparePassword(char[] password) {
|
||||
return Passwords.isExpectedPassword(password, this.salt, this.password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "User{" +
|
||||
"id='" + id + '\'' +
|
||||
", nombre='" + nombre + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
if ( id != null )
|
||||
return id.hashCode();
|
||||
else
|
||||
return super.hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if ( this == o )
|
||||
return true;
|
||||
if ( !(o instanceof Egreso) )
|
||||
return false;
|
||||
|
||||
Egreso other = (Egreso) o;
|
||||
|
||||
if ( id == null )
|
||||
return false;
|
||||
|
||||
return id.equals(other.getId());
|
||||
}
|
||||
}
|
||||
43
src/main/java/xyz/danielcortes/users/UserDAO.java
Executable file
43
src/main/java/xyz/danielcortes/users/UserDAO.java
Executable file
@@ -0,0 +1,43 @@
|
||||
package xyz.danielcortes.users;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import xyz.danielcortes.DAO;
|
||||
import xyz.danielcortes.DB;
|
||||
import xyz.danielcortes.egresos.EgresoDAO;
|
||||
|
||||
public class UserDAO extends DAO<User> {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(EgresoDAO.class);
|
||||
|
||||
public UserDAO(DB db) {
|
||||
super(db, "user", List.of("id", "nombre", "password", "salt"));
|
||||
}
|
||||
|
||||
public User findByNombre(String nombre) {
|
||||
return fetchSingle("select * from usuario where nombre = ?", List.of(nombre));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Object> getColumnsValues(User user) {
|
||||
return List.of(
|
||||
user.getId(),
|
||||
user.getNombre(),
|
||||
user.getPassword(),
|
||||
user.getSalt()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected User mapToEntity(ResultSet rs) throws SQLException {
|
||||
return new User(
|
||||
rs.getString("id"),
|
||||
rs.getString("nombre"),
|
||||
rs.getBytes("password"),
|
||||
rs.getBytes("salt")
|
||||
);
|
||||
}
|
||||
}
|
||||
44
src/main/java/xyz/danielcortes/users/UserRepo.java
Executable file
44
src/main/java/xyz/danielcortes/users/UserRepo.java
Executable file
@@ -0,0 +1,44 @@
|
||||
package xyz.danielcortes.users;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import xyz.danielcortes.Repo;
|
||||
|
||||
public class UserRepo extends Repo<User> {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(UserRepo.class);
|
||||
|
||||
private UserDAO dao;
|
||||
|
||||
public UserRepo(UserDAO dao) {
|
||||
super(dao);
|
||||
this.dao = dao;
|
||||
|
||||
}
|
||||
|
||||
public User getByNombre(String nombre) {
|
||||
for (var user : toAdd.values()) {
|
||||
if (user.getNombre().equals(nombre)) {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
for (var user : toUpdate.values()) {
|
||||
if (user.getNombre().equals(nombre)) {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
var user = dao.findByNombre(nombre);
|
||||
if (user != null && !toRemove.containsKey(user.getId())) {
|
||||
return user;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
24
src/main/resources/app.css
Executable file
24
src/main/resources/app.css
Executable file
@@ -0,0 +1,24 @@
|
||||
.text-input.error {
|
||||
-fx-focus-color: #d35244;
|
||||
-fx-faint-focus-color: #d3524422;
|
||||
|
||||
-fx-highlight-fill: -fx-accent;
|
||||
-fx-highlight-text-fill: white;
|
||||
-fx-background-color: -fx-focus-color,
|
||||
-fx-control-inner-background,
|
||||
-fx-faint-focus-color,
|
||||
linear-gradient(
|
||||
from 0px 0px to 0px 5px,
|
||||
-fx-control-inner-background,
|
||||
-fx-control-inner-background
|
||||
);
|
||||
-fx-background-insets: -0.2, 1, -1.4, 3;
|
||||
-fx-background-radius: 3, 2, 4, 0;
|
||||
-fx-prompt-text-fill: transparent;
|
||||
}
|
||||
|
||||
.border {
|
||||
-fx-border-color: -fx-text-box-border -fx-text-box-border -fx-text-box-border -fx-text-box-border,
|
||||
-fx-shadow-highlight-color -fx-shadow-highlight-color -fx-shadow-highlight-color -fx-shadow-highlight-color;
|
||||
-fx-border-insets: 0, 1 0 0 0;
|
||||
}
|
||||
20
src/main/resources/logback.xml
Executable file
20
src/main/resources/logback.xml
Executable file
@@ -0,0 +1,20 @@
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>[%4level %logger{0}] %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<appender name="file" class="ch.qos.logback.core.FileAppender">
|
||||
<file>file.log</file>
|
||||
<append>false</append>
|
||||
<encoder>
|
||||
<pattern>%4level %logger{0} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="xyz.danielcortes" level="DEBUG">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
<appender-ref ref="file"/>
|
||||
</logger>
|
||||
|
||||
</configuration>
|
||||
58
src/sql/database.sql
Executable file
58
src/sql/database.sql
Executable file
@@ -0,0 +1,58 @@
|
||||
drop database if exists simplefx;
|
||||
create database simplefx;
|
||||
use simplefx;
|
||||
|
||||
create table turno
|
||||
(
|
||||
id char(36) not null,
|
||||
fecha date not null,
|
||||
numero_caja int not null,
|
||||
numero_turno int not null,
|
||||
fondo int not null default 0,
|
||||
inserted_at timestamp not null default now(),
|
||||
modified_at timestamp not null default now() on update now(),
|
||||
constraint unique_turno_fecha_caja_turno unique (fecha, numero_caja, numero_turno),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table egreso
|
||||
(
|
||||
id char(36) not null,
|
||||
nro varchar(255) not null default '',
|
||||
descripcion varchar(255) not null default '',
|
||||
valor int not null default 0,
|
||||
tipo varchar(255) not null default 'Otro',
|
||||
turno_id char(36) not null,
|
||||
inserted_at timestamp not null default now(),
|
||||
modified_at timestamp not null default now() on update now(),
|
||||
foreign key (turno_id) references turno (id),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table ingreso
|
||||
(
|
||||
id char(36) not null,
|
||||
nro int null default '0',
|
||||
ingreso_inicial int not null,
|
||||
ingreso_final int not null,
|
||||
total int not null,
|
||||
tipo_ingreso varchar(255) not null,
|
||||
turno_id char(36) not null,
|
||||
inserted_at timestamp not null default now(),
|
||||
modified_at timestamp not null default now() on update now(),
|
||||
constraint unique_ingreso_turno_tipo unique (turno_id, tipo_ingreso),
|
||||
foreign key (turno_id) references turno (id),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create table usuario
|
||||
(
|
||||
id char(36) not null,
|
||||
nombre varchar(255) not null,
|
||||
password binary(32) not null,
|
||||
salt binary(16) not null,
|
||||
created_at timestamp default now(),
|
||||
modified_at timestamp default now() on update now(),
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user