diff --git a/logs/erp.log b/logs/erp.log
index 52e9dc2..a4ec9eb 100644
--- a/logs/erp.log
+++ b/logs/erp.log
@@ -748,3 +748,393 @@ org.springframework.context.NoSuchMessageException: No message found under code
2026-02-04 18:54:32 WARN [http-nio-8080-exec-7] org.hibernate.orm.query - HHH90003004: firstResult/maxResults specified with collection fetch; applying in memory
2026-02-04 18:54:56 WARN [http-nio-8080-exec-3] org.hibernate.orm.query - HHH90003004: firstResult/maxResults specified with collection fetch; applying in memory
2026-02-04 18:55:47 WARN [http-nio-8080-exec-8] org.hibernate.orm.query - HHH90003004: firstResult/maxResults specified with collection fetch; applying in memory
+2026-02-04 19:10:52 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.10 with PID 29536 (C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros\target\classes started by jjime in C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros)
+2026-02-04 19:10:52 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
+2026-02-04 19:10:56 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
+2026-02-04 19:10:56 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@183104a5
+2026-02-04 19:10:56 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
+2026-02-04 19:10:57 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:10:57 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
+2026-02-04 19:10:57 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:10:57 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
+2026-02-04 19:10:57 INFO [restartedMain] liquibase.util - Run: 0
+2026-02-04 19:10:57 INFO [restartedMain] liquibase.util - Previously run: 69
+2026-02-04 19:10:57 INFO [restartedMain] liquibase.util - Filtered out: 0
+2026-02-04 19:10:57 INFO [restartedMain] liquibase.util - -------------------------------
+2026-02-04 19:10:57 INFO [restartedMain] liquibase.util - Total change sets: 69
+2026-02-04 19:10:57 INFO [restartedMain] liquibase.util - Update summary generated
+2026-02-04 19:10:57 INFO [restartedMain] liquibase.command - Command execution complete
+2026-02-04 19:10:57 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
+2026-02-04 19:10:58 INFO [restartedMain] org.hibernate.Version - HHH000412: Hibernate ORM core version 6.6.39.Final
+2026-02-04 19:10:58 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
+2026-02-04 19:10:58 INFO [restartedMain] o.hibernate.orm.connections.pooling - HHH10001005: Database info:
+ Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-1)']
+ Database driver: undefined/unknown
+ Database version: 8.0.45
+ Autocommit mode: undefined/unknown
+ Isolation level: undefined/unknown
+ Minimum pool size: undefined/unknown
+ Maximum pool size: undefined/unknown
+2026-02-04 19:11:00 INFO [restartedMain] o.h.e.t.j.p.i.JtaPlatformInitiator - HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
+2026-02-04 19:11:04 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 12.701 seconds (process running for 13.526)
+2026-02-04 19:11:34 WARN [http-nio-8080-exec-6] org.hibernate.orm.query - HHH90003004: firstResult/maxResults specified with collection fetch; applying in memory
+2026-02-04 19:16:44 INFO [Thread-5] com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated...
+2026-02-04 19:16:44 INFO [Thread-5] com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed.
+2026-02-04 19:16:44 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.10 with PID 29536 (C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros\target\classes started by jjime in C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros)
+2026-02-04 19:16:44 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
+2026-02-04 19:16:45 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-2 - Starting...
+2026-02-04 19:16:45 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-2 - Added connection com.mysql.cj.jdbc.ConnectionImpl@66447f67
+2026-02-04 19:16:45 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-2 - Start completed.
+2026-02-04 19:16:45 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:16:46 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
+2026-02-04 19:16:46 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:16:46 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
+2026-02-04 19:16:46 INFO [restartedMain] liquibase.util - Run: 0
+2026-02-04 19:16:46 INFO [restartedMain] liquibase.util - Previously run: 69
+2026-02-04 19:16:46 INFO [restartedMain] liquibase.util - Filtered out: 0
+2026-02-04 19:16:46 INFO [restartedMain] liquibase.util - -------------------------------
+2026-02-04 19:16:46 INFO [restartedMain] liquibase.util - Total change sets: 69
+2026-02-04 19:16:46 INFO [restartedMain] liquibase.util - Update summary generated
+2026-02-04 19:16:46 INFO [restartedMain] liquibase.command - Command execution complete
+2026-02-04 19:16:46 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
+2026-02-04 19:16:46 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
+2026-02-04 19:16:46 INFO [restartedMain] o.hibernate.orm.connections.pooling - HHH10001005: Database info:
+ Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-2)']
+ Database driver: undefined/unknown
+ Database version: 8.0.45
+ Autocommit mode: undefined/unknown
+ Isolation level: undefined/unknown
+ Minimum pool size: undefined/unknown
+ Maximum pool size: undefined/unknown
+2026-02-04 19:16:46 INFO [restartedMain] o.h.e.t.j.p.i.JtaPlatformInitiator - HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
+2026-02-04 19:16:47 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 3.535 seconds (process running for 356.622)
+2026-02-04 19:19:10 INFO [Thread-7] com.zaxxer.hikari.HikariDataSource - HikariPool-2 - Shutdown initiated...
+2026-02-04 19:19:10 INFO [Thread-7] com.zaxxer.hikari.HikariDataSource - HikariPool-2 - Shutdown completed.
+2026-02-04 19:19:10 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.10 with PID 29536 (C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros\target\classes started by jjime in C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros)
+2026-02-04 19:19:10 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
+2026-02-04 19:19:11 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-3 - Starting...
+2026-02-04 19:19:11 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-3 - Added connection com.mysql.cj.jdbc.ConnectionImpl@34098173
+2026-02-04 19:19:11 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-3 - Start completed.
+2026-02-04 19:19:11 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:19:11 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
+2026-02-04 19:19:11 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:19:11 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
+2026-02-04 19:19:11 INFO [restartedMain] liquibase.util - Run: 0
+2026-02-04 19:19:11 INFO [restartedMain] liquibase.util - Previously run: 69
+2026-02-04 19:19:11 INFO [restartedMain] liquibase.util - Filtered out: 0
+2026-02-04 19:19:11 INFO [restartedMain] liquibase.util - -------------------------------
+2026-02-04 19:19:11 INFO [restartedMain] liquibase.util - Total change sets: 69
+2026-02-04 19:19:11 INFO [restartedMain] liquibase.util - Update summary generated
+2026-02-04 19:19:11 INFO [restartedMain] liquibase.command - Command execution complete
+2026-02-04 19:19:11 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
+2026-02-04 19:19:11 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
+2026-02-04 19:19:11 INFO [restartedMain] o.hibernate.orm.connections.pooling - HHH10001005: Database info:
+ Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-3)']
+ Database driver: undefined/unknown
+ Database version: 8.0.45
+ Autocommit mode: undefined/unknown
+ Isolation level: undefined/unknown
+ Minimum pool size: undefined/unknown
+ Maximum pool size: undefined/unknown
+2026-02-04 19:19:12 INFO [restartedMain] o.h.e.t.j.p.i.JtaPlatformInitiator - HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
+2026-02-04 19:19:13 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 2.836 seconds (process running for 501.834)
+2026-02-04 19:20:20 INFO [Thread-11] com.zaxxer.hikari.HikariDataSource - HikariPool-3 - Shutdown initiated...
+2026-02-04 19:20:20 INFO [Thread-11] com.zaxxer.hikari.HikariDataSource - HikariPool-3 - Shutdown completed.
+2026-02-04 19:20:20 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.10 with PID 29536 (C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros\target\classes started by jjime in C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros)
+2026-02-04 19:20:20 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
+2026-02-04 19:20:21 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-4 - Starting...
+2026-02-04 19:20:21 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-4 - Added connection com.mysql.cj.jdbc.ConnectionImpl@e1e7a35
+2026-02-04 19:20:21 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-4 - Start completed.
+2026-02-04 19:20:21 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:20:21 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
+2026-02-04 19:20:21 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:20:21 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
+2026-02-04 19:20:21 INFO [restartedMain] liquibase.util - Run: 0
+2026-02-04 19:20:21 INFO [restartedMain] liquibase.util - Previously run: 69
+2026-02-04 19:20:21 INFO [restartedMain] liquibase.util - Filtered out: 0
+2026-02-04 19:20:21 INFO [restartedMain] liquibase.util - -------------------------------
+2026-02-04 19:20:21 INFO [restartedMain] liquibase.util - Total change sets: 69
+2026-02-04 19:20:21 INFO [restartedMain] liquibase.util - Update summary generated
+2026-02-04 19:20:21 INFO [restartedMain] liquibase.command - Command execution complete
+2026-02-04 19:20:21 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
+2026-02-04 19:20:21 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
+2026-02-04 19:20:21 INFO [restartedMain] o.hibernate.orm.connections.pooling - HHH10001005: Database info:
+ Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-4)']
+ Database driver: undefined/unknown
+ Database version: 8.0.45
+ Autocommit mode: undefined/unknown
+ Isolation level: undefined/unknown
+ Minimum pool size: undefined/unknown
+ Maximum pool size: undefined/unknown
+2026-02-04 19:20:22 INFO [restartedMain] o.h.e.t.j.p.i.JtaPlatformInitiator - HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
+2026-02-04 19:20:23 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 2.256 seconds (process running for 571.857)
+2026-02-04 19:20:43 INFO [Thread-15] com.zaxxer.hikari.HikariDataSource - HikariPool-4 - Shutdown initiated...
+2026-02-04 19:20:43 INFO [Thread-15] com.zaxxer.hikari.HikariDataSource - HikariPool-4 - Shutdown completed.
+2026-02-04 19:20:43 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.10 with PID 29536 (C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros\target\classes started by jjime in C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros)
+2026-02-04 19:20:43 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
+2026-02-04 19:20:44 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-5 - Starting...
+2026-02-04 19:20:44 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-5 - Added connection com.mysql.cj.jdbc.ConnectionImpl@63deb5c1
+2026-02-04 19:20:44 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-5 - Start completed.
+2026-02-04 19:20:44 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:20:44 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
+2026-02-04 19:20:44 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:20:44 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
+2026-02-04 19:20:44 INFO [restartedMain] liquibase.util - Run: 0
+2026-02-04 19:20:44 INFO [restartedMain] liquibase.util - Previously run: 69
+2026-02-04 19:20:44 INFO [restartedMain] liquibase.util - Filtered out: 0
+2026-02-04 19:20:44 INFO [restartedMain] liquibase.util - -------------------------------
+2026-02-04 19:20:44 INFO [restartedMain] liquibase.util - Total change sets: 69
+2026-02-04 19:20:44 INFO [restartedMain] liquibase.util - Update summary generated
+2026-02-04 19:20:44 INFO [restartedMain] liquibase.command - Command execution complete
+2026-02-04 19:20:44 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
+2026-02-04 19:20:44 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
+2026-02-04 19:20:44 INFO [restartedMain] o.hibernate.orm.connections.pooling - HHH10001005: Database info:
+ Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-5)']
+ Database driver: undefined/unknown
+ Database version: 8.0.45
+ Autocommit mode: undefined/unknown
+ Isolation level: undefined/unknown
+ Minimum pool size: undefined/unknown
+ Maximum pool size: undefined/unknown
+2026-02-04 19:20:44 INFO [restartedMain] o.h.e.t.j.p.i.JtaPlatformInitiator - HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
+2026-02-04 19:20:45 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 1.959 seconds (process running for 593.959)
+2026-02-04 19:20:54 INFO [Thread-19] com.zaxxer.hikari.HikariDataSource - HikariPool-5 - Shutdown initiated...
+2026-02-04 19:20:54 INFO [Thread-19] com.zaxxer.hikari.HikariDataSource - HikariPool-5 - Shutdown completed.
+2026-02-04 19:20:54 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.10 with PID 29536 (C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros\target\classes started by jjime in C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros)
+2026-02-04 19:20:54 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
+2026-02-04 19:20:54 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-6 - Starting...
+2026-02-04 19:20:54 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-6 - Added connection com.mysql.cj.jdbc.ConnectionImpl@34ac6b55
+2026-02-04 19:20:54 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-6 - Start completed.
+2026-02-04 19:20:55 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:20:55 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
+2026-02-04 19:20:55 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:20:55 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
+2026-02-04 19:20:55 INFO [restartedMain] liquibase.util - Run: 0
+2026-02-04 19:20:55 INFO [restartedMain] liquibase.util - Previously run: 69
+2026-02-04 19:20:55 INFO [restartedMain] liquibase.util - Filtered out: 0
+2026-02-04 19:20:55 INFO [restartedMain] liquibase.util - -------------------------------
+2026-02-04 19:20:55 INFO [restartedMain] liquibase.util - Total change sets: 69
+2026-02-04 19:20:55 INFO [restartedMain] liquibase.util - Update summary generated
+2026-02-04 19:20:55 INFO [restartedMain] liquibase.command - Command execution complete
+2026-02-04 19:20:55 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
+2026-02-04 19:20:55 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
+2026-02-04 19:20:55 INFO [restartedMain] o.hibernate.orm.connections.pooling - HHH10001005: Database info:
+ Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-6)']
+ Database driver: undefined/unknown
+ Database version: 8.0.45
+ Autocommit mode: undefined/unknown
+ Isolation level: undefined/unknown
+ Minimum pool size: undefined/unknown
+ Maximum pool size: undefined/unknown
+2026-02-04 19:20:55 INFO [restartedMain] o.h.e.t.j.p.i.JtaPlatformInitiator - HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
+2026-02-04 19:20:56 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 1.772 seconds (process running for 604.729)
+2026-02-04 19:21:06 INFO [Thread-23] com.zaxxer.hikari.HikariDataSource - HikariPool-6 - Shutdown initiated...
+2026-02-04 19:21:06 INFO [Thread-23] com.zaxxer.hikari.HikariDataSource - HikariPool-6 - Shutdown completed.
+2026-02-04 19:21:06 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.10 with PID 29536 (C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros\target\classes started by jjime in C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros)
+2026-02-04 19:21:06 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
+2026-02-04 19:21:07 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-7 - Starting...
+2026-02-04 19:21:07 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-7 - Added connection com.mysql.cj.jdbc.ConnectionImpl@10784627
+2026-02-04 19:21:07 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-7 - Start completed.
+2026-02-04 19:21:08 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:21:08 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
+2026-02-04 19:21:08 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:21:08 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
+2026-02-04 19:21:08 INFO [restartedMain] liquibase.util - Run: 0
+2026-02-04 19:21:08 INFO [restartedMain] liquibase.util - Previously run: 69
+2026-02-04 19:21:08 INFO [restartedMain] liquibase.util - Filtered out: 0
+2026-02-04 19:21:08 INFO [restartedMain] liquibase.util - -------------------------------
+2026-02-04 19:21:08 INFO [restartedMain] liquibase.util - Total change sets: 69
+2026-02-04 19:21:08 INFO [restartedMain] liquibase.util - Update summary generated
+2026-02-04 19:21:08 INFO [restartedMain] liquibase.command - Command execution complete
+2026-02-04 19:21:08 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
+2026-02-04 19:21:08 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
+2026-02-04 19:21:08 INFO [restartedMain] o.hibernate.orm.connections.pooling - HHH10001005: Database info:
+ Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-7)']
+ Database driver: undefined/unknown
+ Database version: 8.0.45
+ Autocommit mode: undefined/unknown
+ Isolation level: undefined/unknown
+ Minimum pool size: undefined/unknown
+ Maximum pool size: undefined/unknown
+2026-02-04 19:21:08 INFO [restartedMain] o.h.e.t.j.p.i.JtaPlatformInitiator - HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
+2026-02-04 19:21:10 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 3.395 seconds (process running for 618.722)
+2026-02-04 19:21:59 INFO [Thread-27] com.zaxxer.hikari.HikariDataSource - HikariPool-7 - Shutdown initiated...
+2026-02-04 19:21:59 INFO [Thread-27] com.zaxxer.hikari.HikariDataSource - HikariPool-7 - Shutdown completed.
+2026-02-04 19:21:59 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.10 with PID 29536 (C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros\target\classes started by jjime in C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros)
+2026-02-04 19:21:59 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
+2026-02-04 19:22:00 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-8 - Starting...
+2026-02-04 19:22:00 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-8 - Added connection com.mysql.cj.jdbc.ConnectionImpl@41c31f82
+2026-02-04 19:22:00 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-8 - Start completed.
+2026-02-04 19:22:00 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:22:00 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
+2026-02-04 19:22:00 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:22:00 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
+2026-02-04 19:22:00 INFO [restartedMain] liquibase.util - Run: 0
+2026-02-04 19:22:00 INFO [restartedMain] liquibase.util - Previously run: 69
+2026-02-04 19:22:00 INFO [restartedMain] liquibase.util - Filtered out: 0
+2026-02-04 19:22:00 INFO [restartedMain] liquibase.util - -------------------------------
+2026-02-04 19:22:00 INFO [restartedMain] liquibase.util - Total change sets: 69
+2026-02-04 19:22:00 INFO [restartedMain] liquibase.util - Update summary generated
+2026-02-04 19:22:00 INFO [restartedMain] liquibase.command - Command execution complete
+2026-02-04 19:22:00 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
+2026-02-04 19:22:00 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
+2026-02-04 19:22:00 INFO [restartedMain] o.hibernate.orm.connections.pooling - HHH10001005: Database info:
+ Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-8)']
+ Database driver: undefined/unknown
+ Database version: 8.0.45
+ Autocommit mode: undefined/unknown
+ Isolation level: undefined/unknown
+ Minimum pool size: undefined/unknown
+ Maximum pool size: undefined/unknown
+2026-02-04 19:22:00 INFO [restartedMain] o.h.e.t.j.p.i.JtaPlatformInitiator - HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
+2026-02-04 19:22:01 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 1.628 seconds (process running for 670.213)
+2026-02-04 19:22:11 INFO [Thread-31] com.zaxxer.hikari.HikariDataSource - HikariPool-8 - Shutdown initiated...
+2026-02-04 19:22:11 INFO [Thread-31] com.zaxxer.hikari.HikariDataSource - HikariPool-8 - Shutdown completed.
+2026-02-04 19:22:12 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.10 with PID 29536 (C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros\target\classes started by jjime in C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros)
+2026-02-04 19:22:12 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
+2026-02-04 19:22:12 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-9 - Starting...
+2026-02-04 19:22:12 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-9 - Added connection com.mysql.cj.jdbc.ConnectionImpl@1711d305
+2026-02-04 19:22:12 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-9 - Start completed.
+2026-02-04 19:22:12 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:22:12 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
+2026-02-04 19:22:12 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:22:12 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
+2026-02-04 19:22:12 INFO [restartedMain] liquibase.util - Run: 0
+2026-02-04 19:22:12 INFO [restartedMain] liquibase.util - Previously run: 69
+2026-02-04 19:22:12 INFO [restartedMain] liquibase.util - Filtered out: 0
+2026-02-04 19:22:12 INFO [restartedMain] liquibase.util - -------------------------------
+2026-02-04 19:22:12 INFO [restartedMain] liquibase.util - Total change sets: 69
+2026-02-04 19:22:12 INFO [restartedMain] liquibase.util - Update summary generated
+2026-02-04 19:22:12 INFO [restartedMain] liquibase.command - Command execution complete
+2026-02-04 19:22:12 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
+2026-02-04 19:22:12 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
+2026-02-04 19:22:12 INFO [restartedMain] o.hibernate.orm.connections.pooling - HHH10001005: Database info:
+ Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-9)']
+ Database driver: undefined/unknown
+ Database version: 8.0.45
+ Autocommit mode: undefined/unknown
+ Isolation level: undefined/unknown
+ Minimum pool size: undefined/unknown
+ Maximum pool size: undefined/unknown
+2026-02-04 19:22:12 INFO [restartedMain] o.h.e.t.j.p.i.JtaPlatformInitiator - HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
+2026-02-04 19:22:13 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 1.598 seconds (process running for 682.299)
+2026-02-04 19:22:20 INFO [Thread-35] com.zaxxer.hikari.HikariDataSource - HikariPool-9 - Shutdown initiated...
+2026-02-04 19:22:20 INFO [Thread-35] com.zaxxer.hikari.HikariDataSource - HikariPool-9 - Shutdown completed.
+2026-02-04 19:22:20 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.10 with PID 29536 (C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros\target\classes started by jjime in C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros)
+2026-02-04 19:22:20 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
+2026-02-04 19:22:21 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-10 - Starting...
+2026-02-04 19:22:21 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-10 - Added connection com.mysql.cj.jdbc.ConnectionImpl@821ce2f
+2026-02-04 19:22:21 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-10 - Start completed.
+2026-02-04 19:22:21 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:22:21 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
+2026-02-04 19:22:21 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:22:21 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
+2026-02-04 19:22:21 INFO [restartedMain] liquibase.util - Run: 0
+2026-02-04 19:22:21 INFO [restartedMain] liquibase.util - Previously run: 69
+2026-02-04 19:22:21 INFO [restartedMain] liquibase.util - Filtered out: 0
+2026-02-04 19:22:21 INFO [restartedMain] liquibase.util - -------------------------------
+2026-02-04 19:22:21 INFO [restartedMain] liquibase.util - Total change sets: 69
+2026-02-04 19:22:21 INFO [restartedMain] liquibase.util - Update summary generated
+2026-02-04 19:22:21 INFO [restartedMain] liquibase.command - Command execution complete
+2026-02-04 19:22:21 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
+2026-02-04 19:22:21 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
+2026-02-04 19:22:21 INFO [restartedMain] o.hibernate.orm.connections.pooling - HHH10001005: Database info:
+ Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-10)']
+ Database driver: undefined/unknown
+ Database version: 8.0.45
+ Autocommit mode: undefined/unknown
+ Isolation level: undefined/unknown
+ Minimum pool size: undefined/unknown
+ Maximum pool size: undefined/unknown
+2026-02-04 19:22:21 INFO [restartedMain] o.h.e.t.j.p.i.JtaPlatformInitiator - HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
+2026-02-04 19:22:22 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 1.659 seconds (process running for 691.219)
+2026-02-04 19:22:34 INFO [Thread-39] com.zaxxer.hikari.HikariDataSource - HikariPool-10 - Shutdown initiated...
+2026-02-04 19:22:34 INFO [Thread-39] com.zaxxer.hikari.HikariDataSource - HikariPool-10 - Shutdown completed.
+2026-02-04 19:22:34 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.10 with PID 29536 (C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros\target\classes started by jjime in C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros)
+2026-02-04 19:22:34 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
+2026-02-04 19:22:35 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-11 - Starting...
+2026-02-04 19:22:35 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-11 - Added connection com.mysql.cj.jdbc.ConnectionImpl@3b357f77
+2026-02-04 19:22:35 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-11 - Start completed.
+2026-02-04 19:22:35 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:22:35 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
+2026-02-04 19:22:35 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:22:35 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
+2026-02-04 19:22:35 INFO [restartedMain] liquibase.util - Run: 0
+2026-02-04 19:22:35 INFO [restartedMain] liquibase.util - Previously run: 69
+2026-02-04 19:22:35 INFO [restartedMain] liquibase.util - Filtered out: 0
+2026-02-04 19:22:35 INFO [restartedMain] liquibase.util - -------------------------------
+2026-02-04 19:22:35 INFO [restartedMain] liquibase.util - Total change sets: 69
+2026-02-04 19:22:35 INFO [restartedMain] liquibase.util - Update summary generated
+2026-02-04 19:22:35 INFO [restartedMain] liquibase.command - Command execution complete
+2026-02-04 19:22:35 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
+2026-02-04 19:22:35 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
+2026-02-04 19:22:35 INFO [restartedMain] o.hibernate.orm.connections.pooling - HHH10001005: Database info:
+ Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-11)']
+ Database driver: undefined/unknown
+ Database version: 8.0.45
+ Autocommit mode: undefined/unknown
+ Isolation level: undefined/unknown
+ Minimum pool size: undefined/unknown
+ Maximum pool size: undefined/unknown
+2026-02-04 19:22:35 INFO [restartedMain] o.h.e.t.j.p.i.JtaPlatformInitiator - HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
+2026-02-04 19:22:36 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 1.688 seconds (process running for 704.975)
+2026-02-04 19:22:45 INFO [Thread-43] com.zaxxer.hikari.HikariDataSource - HikariPool-11 - Shutdown initiated...
+2026-02-04 19:22:45 INFO [Thread-43] com.zaxxer.hikari.HikariDataSource - HikariPool-11 - Shutdown completed.
+2026-02-04 19:22:45 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.10 with PID 29536 (C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros\target\classes started by jjime in C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros)
+2026-02-04 19:22:45 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
+2026-02-04 19:22:45 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-12 - Starting...
+2026-02-04 19:22:45 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-12 - Added connection com.mysql.cj.jdbc.ConnectionImpl@36500de4
+2026-02-04 19:22:45 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-12 - Start completed.
+2026-02-04 19:22:45 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:22:45 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
+2026-02-04 19:22:45 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:22:45 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
+2026-02-04 19:22:45 INFO [restartedMain] liquibase.util - Run: 0
+2026-02-04 19:22:45 INFO [restartedMain] liquibase.util - Previously run: 69
+2026-02-04 19:22:45 INFO [restartedMain] liquibase.util - Filtered out: 0
+2026-02-04 19:22:45 INFO [restartedMain] liquibase.util - -------------------------------
+2026-02-04 19:22:45 INFO [restartedMain] liquibase.util - Total change sets: 69
+2026-02-04 19:22:45 INFO [restartedMain] liquibase.util - Update summary generated
+2026-02-04 19:22:45 INFO [restartedMain] liquibase.command - Command execution complete
+2026-02-04 19:22:45 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
+2026-02-04 19:22:45 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
+2026-02-04 19:22:45 INFO [restartedMain] o.hibernate.orm.connections.pooling - HHH10001005: Database info:
+ Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-12)']
+ Database driver: undefined/unknown
+ Database version: 8.0.45
+ Autocommit mode: undefined/unknown
+ Isolation level: undefined/unknown
+ Minimum pool size: undefined/unknown
+ Maximum pool size: undefined/unknown
+2026-02-04 19:22:46 INFO [restartedMain] o.h.e.t.j.p.i.JtaPlatformInitiator - HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
+2026-02-04 19:22:46 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 1.575 seconds (process running for 715.38)
+2026-02-04 19:22:57 INFO [Thread-47] com.zaxxer.hikari.HikariDataSource - HikariPool-12 - Shutdown initiated...
+2026-02-04 19:22:57 INFO [Thread-47] com.zaxxer.hikari.HikariDataSource - HikariPool-12 - Shutdown completed.
+2026-02-04 19:22:57 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.10 with PID 29536 (C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros\target\classes started by jjime in C:\Users\jjime\Documents\00_DESIGN_NOTEBOOK\PROGRAMMING\erp-imprimelibros)
+2026-02-04 19:22:57 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
+2026-02-04 19:22:57 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-13 - Starting...
+2026-02-04 19:22:57 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-13 - Added connection com.mysql.cj.jdbc.ConnectionImpl@3d063cf3
+2026-02-04 19:22:57 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-13 - Start completed.
+2026-02-04 19:22:57 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:22:57 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
+2026-02-04 19:22:57 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
+2026-02-04 19:22:57 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
+2026-02-04 19:22:57 INFO [restartedMain] liquibase.util - Run: 0
+2026-02-04 19:22:57 INFO [restartedMain] liquibase.util - Previously run: 69
+2026-02-04 19:22:57 INFO [restartedMain] liquibase.util - Filtered out: 0
+2026-02-04 19:22:57 INFO [restartedMain] liquibase.util - -------------------------------
+2026-02-04 19:22:57 INFO [restartedMain] liquibase.util - Total change sets: 69
+2026-02-04 19:22:57 INFO [restartedMain] liquibase.util - Update summary generated
+2026-02-04 19:22:57 INFO [restartedMain] liquibase.command - Command execution complete
+2026-02-04 19:22:57 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
+2026-02-04 19:22:57 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
+2026-02-04 19:22:57 INFO [restartedMain] o.hibernate.orm.connections.pooling - HHH10001005: Database info:
+ Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-13)']
+ Database driver: undefined/unknown
+ Database version: 8.0.45
+ Autocommit mode: undefined/unknown
+ Isolation level: undefined/unknown
+ Minimum pool size: undefined/unknown
+ Maximum pool size: undefined/unknown
+2026-02-04 19:22:58 INFO [restartedMain] o.h.e.t.j.p.i.JtaPlatformInitiator - HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
+2026-02-04 19:22:58 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 1.446 seconds (process running for 727.328)
diff --git a/src/main/java/com/imprimelibros/erp/users/ProfileController.java b/src/main/java/com/imprimelibros/erp/users/ProfileController.java
new file mode 100644
index 0000000..a43fbd4
--- /dev/null
+++ b/src/main/java/com/imprimelibros/erp/users/ProfileController.java
@@ -0,0 +1,155 @@
+package com.imprimelibros.erp.users;
+
+import java.util.Locale;
+
+import org.springframework.context.MessageSource;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.validation.BindingResult;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.servlet.mvc.support.RedirectAttributes;
+
+import com.imprimelibros.erp.config.Sanitizer;
+import com.imprimelibros.erp.users.validation.ProfileForm;
+
+@Controller
+@RequestMapping("/pages-profile")
+@PreAuthorize("isAuthenticated()")
+public class ProfileController {
+
+ private final UserDao userDao;
+ private final PasswordEncoder passwordEncoder;
+ private final MessageSource messageSource;
+ private final Sanitizer sanitizer;
+
+ public ProfileController(UserDao userDao, PasswordEncoder passwordEncoder,
+ MessageSource messageSource, Sanitizer sanitizer) {
+ this.userDao = userDao;
+ this.passwordEncoder = passwordEncoder;
+ this.messageSource = messageSource;
+ this.sanitizer = sanitizer;
+ }
+
+ @GetMapping
+ public String view(
+ Authentication authentication,
+ @RequestParam(name = "success", required = false) String success,
+ Model model,
+ Locale locale) {
+
+ if (authentication == null) {
+ return "redirect:/login";
+ }
+
+ User user = userDao.findByUserNameIgnoreCase(authentication.getName()).orElse(null);
+ if (user == null) {
+ return "redirect:/login";
+ }
+
+ ProfileForm form = new ProfileForm();
+ form.setId(user.getId());
+ form.setFullName(user.getFullName());
+ form.setUserName(user.getUserName());
+
+ model.addAttribute("user", form);
+ model.addAttribute("success", success != null);
+ return "imprimelibros/users/profile";
+ }
+
+ @PostMapping
+ public String update(
+ Authentication authentication,
+ @Validated @ModelAttribute("user") ProfileForm form,
+ BindingResult binding,
+ Model model,
+ RedirectAttributes redirectAttributes,
+ Locale locale) {
+
+ if (authentication == null) {
+ return "redirect:/login";
+ }
+
+ User user = userDao.findByUserNameIgnoreCase(authentication.getName()).orElse(null);
+ if (user == null) {
+ return "redirect:/login";
+ }
+
+ String normalized = sanitizer.plain(form.getUserName());
+ if (normalized != null) {
+ normalized = normalized.trim().toLowerCase();
+ }
+
+ if (normalized == null || normalized.isBlank()) {
+ binding.rejectValue("userName", "usuarios.error.email",
+ messageSource.getMessage("usuarios.error.email", null, locale));
+ } else if (userDao.existsByUserNameIgnoreCaseAndIdNot(normalized, user.getId())) {
+ binding.rejectValue("userName", "usuarios.error.duplicado",
+ messageSource.getMessage("usuarios.error.duplicado", null, locale));
+ }
+
+ String cleanName = sanitizer.plain(form.getFullName());
+ if (cleanName == null || cleanName.isBlank()) {
+ binding.rejectValue("fullName", "usuarios.error.nombre",
+ messageSource.getMessage("usuarios.error.nombre", null, locale));
+ }
+
+ boolean wantsPasswordChange = hasText(form.getCurrentPassword())
+ || hasText(form.getNewPassword())
+ || hasText(form.getConfirmPassword());
+
+ if (wantsPasswordChange) {
+ if (!hasText(form.getCurrentPassword())) {
+ binding.rejectValue("currentPassword", "usuarios.error.password.actual",
+ messageSource.getMessage("usuarios.error.password.actual", null, locale));
+ } else if (!passwordEncoder.matches(form.getCurrentPassword(), user.getPassword())) {
+ binding.rejectValue("currentPassword", "usuarios.error.password.actual.incorrecta",
+ messageSource.getMessage("usuarios.error.password.actual.incorrecta", null, locale));
+ }
+
+ if (!hasText(form.getNewPassword())) {
+ binding.rejectValue("newPassword", "usuarios.error.password.nueva.requerida",
+ messageSource.getMessage("usuarios.error.password.nueva.requerida", null, locale));
+ } else if (form.getNewPassword().length() < 6) {
+ binding.rejectValue("newPassword", "usuarios.error.password.min",
+ messageSource.getMessage("usuarios.error.password.min", null, locale));
+ }
+
+ if (!hasText(form.getConfirmPassword())) {
+ binding.rejectValue("confirmPassword", "usuarios.error.confirmPassword.requerida",
+ messageSource.getMessage("usuarios.error.confirmPassword.requerida", null, locale));
+ } else if (hasText(form.getNewPassword()) && !form.getNewPassword().equals(form.getConfirmPassword())) {
+ binding.rejectValue("confirmPassword", "usuarios.error.password-coinciden",
+ messageSource.getMessage("usuarios.error.password-coinciden", null, locale));
+ }
+ }
+
+ if (binding.hasErrors()) {
+ model.addAttribute("success", false);
+ return "imprimelibros/users/profile";
+ }
+
+ user.setFullName(cleanName.trim());
+ user.setUserName(normalized);
+
+ if (wantsPasswordChange) {
+ user.setPassword(passwordEncoder.encode(form.getNewPassword()));
+ }
+
+ userDao.save(user);
+
+ redirectAttributes.addAttribute("success", "1");
+ return "redirect:/pages-profile";
+ }
+
+ private static boolean hasText(String value) {
+ return value != null && !value.isBlank();
+ }
+}
diff --git a/src/main/java/com/imprimelibros/erp/users/validation/ProfileForm.java b/src/main/java/com/imprimelibros/erp/users/validation/ProfileForm.java
new file mode 100644
index 0000000..0055444
--- /dev/null
+++ b/src/main/java/com/imprimelibros/erp/users/validation/ProfileForm.java
@@ -0,0 +1,68 @@
+package com.imprimelibros.erp.users.validation;
+
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotBlank;
+
+public class ProfileForm {
+
+ private Long id;
+
+ @NotBlank(message = "{usuarios.error.nombre}")
+ private String fullName;
+
+ @NotBlank(message = "{usuarios.error.email}")
+ @Email(message = "{usuarios.error.email.formato}")
+ private String userName;
+
+ private String currentPassword;
+ private String newPassword;
+ private String confirmPassword;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getFullName() {
+ return fullName;
+ }
+
+ public void setFullName(String fullName) {
+ this.fullName = fullName;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ public String getCurrentPassword() {
+ return currentPassword;
+ }
+
+ public void setCurrentPassword(String currentPassword) {
+ this.currentPassword = currentPassword;
+ }
+
+ public String getNewPassword() {
+ return newPassword;
+ }
+
+ public void setNewPassword(String newPassword) {
+ this.newPassword = newPassword;
+ }
+
+ public String getConfirmPassword() {
+ return confirmPassword;
+ }
+
+ public void setConfirmPassword(String confirmPassword) {
+ this.confirmPassword = confirmPassword;
+ }
+}
diff --git a/src/main/resources/i18n/users_en.properties b/src/main/resources/i18n/users_en.properties
index 73daca1..9f1b17e 100644
--- a/src/main/resources/i18n/users_en.properties
+++ b/src/main/resources/i18n/users_en.properties
@@ -1,3 +1,23 @@
+usuarios.form.nombre=Full name
+usuarios.form.email=Email
+usuarios.form.confirmarPassword=Confirm password
+usuarios.form.password.actual=Current password
+usuarios.form.password.nueva=New password
+usuarios.form.password.nota=You can only change the password if you provide the current one.
+
+usuarios.error.nombre=Name is required.
+usuarios.error.email=Email is required.
+usuarios.error.email.formato=Email is not valid.
+usuarios.error.password.min=Password must be at least 6 characters.
+usuarios.error.password.actual=Current password is required.
+usuarios.error.password.actual.incorrecta=Current password is not correct.
+usuarios.error.password.nueva.requerida=New password is required.
+usuarios.error.confirmPassword.requerida=Password confirmation is required.
+usuarios.error.password-coinciden=Passwords do not match.
+usuarios.error.duplicado=There is already a user with that email.
+
usuarios.impersonate.title=Sign in as user
usuarios.impersonate.text=You are about to sign in as {0}. You can return to your user from the menu.
usuarios.impersonate.button=Continue
+usuarios.profile.title=Edit profile
+usuarios.profile.success=Profile updated successfully.
diff --git a/src/main/resources/i18n/users_es.properties b/src/main/resources/i18n/users_es.properties
index c528825..fcd1b40 100644
--- a/src/main/resources/i18n/users_es.properties
+++ b/src/main/resources/i18n/users_es.properties
@@ -20,6 +20,9 @@ usuarios.form.nombre=Nombre completo
usuarios.form.email=Correo electrónico
usuarios.form.password=Contraseña
usuarios.form.confirmarPassword=Confirmar contraseña
+usuarios.form.password.actual=Contraseña actual
+usuarios.form.password.nueva=Nueva contraseña
+usuarios.form.password.nota=Solo podrás cambiar la contraseña si indicas la actual.
usuarios.form.rol=Rol
usuarios.form.estado=Estado
@@ -37,6 +40,9 @@ usuarios.error.email.formato=El correo electrónico no es válido.
usuarios.error.rol=El rol seleccionado no es válido.
usuarios.error.password.requerida=La contraseña es obligatoria.
usuarios.error.password.min=La contraseña debe tener al menos 6 caracteres.
+usuarios.error.password.actual=La contraseña actual es obligatoria.
+usuarios.error.password.actual.incorrecta=La contraseña actual no es correcta.
+usuarios.error.password.nueva.requerida=La nueva contraseña es obligatoria.
usuarios.error.confirmPassword.requerida=La confirmación de la contraseña es obligatoria.
usuarios.error.password-coinciden=Las contraseñas no coinciden.
usuarios.error.delete-relational-data=No se puede eliminar el usuario porque tiene datos relacionados.
@@ -55,5 +61,7 @@ usuarios.delete.text=¿Está seguro de que desea eliminar al usuario?
Esta ac
usuarios.delete.ok.title=Usuario eliminado
usuarios.delete.ok.text=El usuario ha sido eliminado con éxito.
usuarios.impersonate.title=Entrar como usuario
-usuarios.impersonate.text=Vas a iniciar sesión como {0}. Podrás volver a tu usuario desde el menú.
+usuarios.impersonate.text=Vas a iniciar sesión como {0}. Podrás volver a tu usuario desde el menú.
usuarios.impersonate.button=Entrar
+usuarios.profile.title=Editar perfil
+usuarios.profile.success=Perfil actualizado correctamente.
diff --git a/src/main/resources/templates/imprimelibros/partials/topbar.html b/src/main/resources/templates/imprimelibros/partials/topbar.html
index a8f5dc1..f58ea4a 100644
--- a/src/main/resources/templates/imprimelibros/partials/topbar.html
+++ b/src/main/resources/templates/imprimelibros/partials/topbar.html
@@ -100,9 +100,6 @@
Perfil
-
- Mensajes