mirror of
https://git.imnavajas.es/jjimenez/erp-imprimelibros.git
synced 2026-03-01 06:09:13 +00:00
Compare commits
26 Commits
292aebcf65
...
fix/import
| Author | SHA1 | Date | |
|---|---|---|---|
| 35967b93a0 | |||
| cef0af1bd2 | |||
| 8282c92419 | |||
| 433a055b14 | |||
| fe4d180e2d | |||
| cc2d2ef193 | |||
| 11a5918c37 | |||
| 88769ddaeb | |||
| 9acb105127 | |||
| 6dab15afbc | |||
| a0783c2062 | |||
| d0ccfb5626 | |||
| 2e569a7ffd | |||
| bc8ce4fa81 | |||
| 1bfe0cf3a2 | |||
| 61e55e014f | |||
| 06a3521f6b | |||
| ecf1472f58 | |||
| 48993a34c4 | |||
| a0bf8552f1 | |||
| 562dc2b231 | |||
| 9a49ccf6b8 | |||
| b2026f1cab | |||
| a5b6bf3a25 | |||
| 9a67c2e78f | |||
| 8263d97bf7 |
4
.gitignore
vendored
4
.gitignore
vendored
@ -33,4 +33,6 @@ build/
|
||||
.vscode/
|
||||
|
||||
### Logs ###
|
||||
erp-*.log
|
||||
/Logs/
|
||||
erp.log
|
||||
erp*.log
|
||||
|
||||
701
logs/erp.log
701
logs/erp.log
@ -1,701 +0,0 @@
|
||||
2026-01-04 11:55:35 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.9 with PID 8855 (/home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros/target/classes started by jjimenez in /home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros)
|
||||
2026-01-04 11:55:35 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
|
||||
2026-01-04 11:55:40 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
|
||||
2026-01-04 11:55:41 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@40e3206c
|
||||
2026-01-04 11:55:41 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
|
||||
2026-01-04 11:55:42 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 11:55:42 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
|
||||
2026-01-04 11:55:42 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 11:55:42 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
|
||||
2026-01-04 11:55:42 INFO [restartedMain] liquibase.util - Run: 0
|
||||
2026-01-04 11:55:42 INFO [restartedMain] liquibase.util - Previously run: 67
|
||||
2026-01-04 11:55:42 INFO [restartedMain] liquibase.util - Filtered out: 0
|
||||
2026-01-04 11:55:42 INFO [restartedMain] liquibase.util - -------------------------------
|
||||
2026-01-04 11:55:42 INFO [restartedMain] liquibase.util - Total change sets: 67
|
||||
2026-01-04 11:55:42 INFO [restartedMain] liquibase.util - Update summary generated
|
||||
2026-01-04 11:55:42 INFO [restartedMain] liquibase.command - Command execution complete
|
||||
2026-01-04 11:55:43 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
|
||||
2026-01-04 11:55:43 INFO [restartedMain] org.hibernate.Version - HHH000412: Hibernate ORM core version 6.6.39.Final
|
||||
2026-01-04 11:55:43 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
|
||||
2026-01-04 11:55:43 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.43
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: undefined/unknown
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
2026-01-04 11:55: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-01-04 11:55:52 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 17.254 seconds (process running for 18.958)
|
||||
2026-01-04 11:56:14 WARN [http-nio-8080-exec-3] o.a.pdfbox.pdmodel.font.PDType1Font - Using fallback font LiberationSans for base font Symbol
|
||||
2026-01-04 11:56:14 WARN [http-nio-8080-exec-3] o.a.pdfbox.pdmodel.font.PDType1Font - Using fallback font LiberationSans for base font ZapfDingbats
|
||||
2026-01-04 12:13:22 INFO [Thread-5] com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated...
|
||||
2026-01-04 12:13:22 INFO [Thread-5] com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed.
|
||||
2026-01-04 12:13:22 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.9 with PID 8855 (/home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros/target/classes started by jjimenez in /home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros)
|
||||
2026-01-04 12:13:22 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
|
||||
2026-01-04 12:13:23 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-2 - Starting...
|
||||
2026-01-04 12:13:23 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-2 - Added connection com.mysql.cj.jdbc.ConnectionImpl@639ded37
|
||||
2026-01-04 12:13:23 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-2 - Start completed.
|
||||
2026-01-04 12:13:24 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 12:13:24 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
|
||||
2026-01-04 12:13:24 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 12:13:24 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
|
||||
2026-01-04 12:13:24 INFO [restartedMain] liquibase.util - Run: 0
|
||||
2026-01-04 12:13:24 INFO [restartedMain] liquibase.util - Previously run: 67
|
||||
2026-01-04 12:13:24 INFO [restartedMain] liquibase.util - Filtered out: 0
|
||||
2026-01-04 12:13:24 INFO [restartedMain] liquibase.util - -------------------------------
|
||||
2026-01-04 12:13:24 INFO [restartedMain] liquibase.util - Total change sets: 67
|
||||
2026-01-04 12:13:24 INFO [restartedMain] liquibase.util - Update summary generated
|
||||
2026-01-04 12:13:24 INFO [restartedMain] liquibase.command - Command execution complete
|
||||
2026-01-04 12:13:24 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
|
||||
2026-01-04 12:13:24 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
|
||||
2026-01-04 12:13:24 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.43
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: undefined/unknown
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
2026-01-04 12:13:25 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-01-04 12:13:27 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 4.858 seconds (process running for 1074.089)
|
||||
2026-01-04 12:16:06 INFO [Thread-7] com.zaxxer.hikari.HikariDataSource - HikariPool-2 - Shutdown initiated...
|
||||
2026-01-04 12:16:06 INFO [Thread-7] com.zaxxer.hikari.HikariDataSource - HikariPool-2 - Shutdown completed.
|
||||
2026-01-04 12:16:06 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.9 with PID 8855 (/home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros/target/classes started by jjimenez in /home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros)
|
||||
2026-01-04 12:16:06 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
|
||||
2026-01-04 12:16:07 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-3 - Starting...
|
||||
2026-01-04 12:16:07 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-3 - Added connection com.mysql.cj.jdbc.ConnectionImpl@3be3ffed
|
||||
2026-01-04 12:16:07 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-3 - Start completed.
|
||||
2026-01-04 12:16:07 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 12:16:07 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
|
||||
2026-01-04 12:16:07 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 12:16:07 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
|
||||
2026-01-04 12:16:07 INFO [restartedMain] liquibase.util - Run: 0
|
||||
2026-01-04 12:16:07 INFO [restartedMain] liquibase.util - Previously run: 67
|
||||
2026-01-04 12:16:07 INFO [restartedMain] liquibase.util - Filtered out: 0
|
||||
2026-01-04 12:16:07 INFO [restartedMain] liquibase.util - -------------------------------
|
||||
2026-01-04 12:16:07 INFO [restartedMain] liquibase.util - Total change sets: 67
|
||||
2026-01-04 12:16:07 INFO [restartedMain] liquibase.util - Update summary generated
|
||||
2026-01-04 12:16:07 INFO [restartedMain] liquibase.command - Command execution complete
|
||||
2026-01-04 12:16:07 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
|
||||
2026-01-04 12:16:07 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
|
||||
2026-01-04 12:16:07 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.43
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: undefined/unknown
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
2026-01-04 12:16: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-01-04 12:16:09 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 3.656 seconds (process running for 1236.914)
|
||||
2026-01-04 12:17:14 INFO [Thread-11] com.zaxxer.hikari.HikariDataSource - HikariPool-3 - Shutdown initiated...
|
||||
2026-01-04 12:17:14 INFO [Thread-11] com.zaxxer.hikari.HikariDataSource - HikariPool-3 - Shutdown completed.
|
||||
2026-01-04 12:17:14 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.9 with PID 8855 (/home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros/target/classes started by jjimenez in /home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros)
|
||||
2026-01-04 12:17:14 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
|
||||
2026-01-04 12:17:16 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-4 - Starting...
|
||||
2026-01-04 12:17:16 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-4 - Added connection com.mysql.cj.jdbc.ConnectionImpl@3b7c2a33
|
||||
2026-01-04 12:17:16 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-4 - Start completed.
|
||||
2026-01-04 12:17:16 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 12:17:16 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
|
||||
2026-01-04 12:17:16 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 12:17:16 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
|
||||
2026-01-04 12:17:16 INFO [restartedMain] liquibase.util - Run: 0
|
||||
2026-01-04 12:17:16 INFO [restartedMain] liquibase.util - Previously run: 67
|
||||
2026-01-04 12:17:16 INFO [restartedMain] liquibase.util - Filtered out: 0
|
||||
2026-01-04 12:17:16 INFO [restartedMain] liquibase.util - -------------------------------
|
||||
2026-01-04 12:17:16 INFO [restartedMain] liquibase.util - Total change sets: 67
|
||||
2026-01-04 12:17:16 INFO [restartedMain] liquibase.util - Update summary generated
|
||||
2026-01-04 12:17:16 INFO [restartedMain] liquibase.command - Command execution complete
|
||||
2026-01-04 12:17:16 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
|
||||
2026-01-04 12:17:16 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
|
||||
2026-01-04 12:17:16 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.43
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: undefined/unknown
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
2026-01-04 12:17:17 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-01-04 12:17:18 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 3.458 seconds (process running for 1305.332)
|
||||
2026-01-04 12:42:37 INFO [Thread-15] com.zaxxer.hikari.HikariDataSource - HikariPool-4 - Shutdown initiated...
|
||||
2026-01-04 12:42:37 INFO [Thread-15] com.zaxxer.hikari.HikariDataSource - HikariPool-4 - Shutdown completed.
|
||||
2026-01-04 12:42:37 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.9 with PID 8855 (/home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros/target/classes started by jjimenez in /home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros)
|
||||
2026-01-04 12:42:37 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
|
||||
2026-01-04 12:42:39 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-5 - Starting...
|
||||
2026-01-04 12:42:39 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-5 - Added connection com.mysql.cj.jdbc.ConnectionImpl@3932cc06
|
||||
2026-01-04 12:42:39 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-5 - Start completed.
|
||||
2026-01-04 12:42:40 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 12:42:40 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
|
||||
2026-01-04 12:42:40 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 12:42:40 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
|
||||
2026-01-04 12:42:40 INFO [restartedMain] liquibase.util - Run: 0
|
||||
2026-01-04 12:42:40 INFO [restartedMain] liquibase.util - Previously run: 67
|
||||
2026-01-04 12:42:40 INFO [restartedMain] liquibase.util - Filtered out: 0
|
||||
2026-01-04 12:42:40 INFO [restartedMain] liquibase.util - -------------------------------
|
||||
2026-01-04 12:42:40 INFO [restartedMain] liquibase.util - Total change sets: 67
|
||||
2026-01-04 12:42:40 INFO [restartedMain] liquibase.util - Update summary generated
|
||||
2026-01-04 12:42:40 INFO [restartedMain] liquibase.command - Command execution complete
|
||||
2026-01-04 12:42:40 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
|
||||
2026-01-04 12:42:40 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
|
||||
2026-01-04 12:42:40 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.43
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: undefined/unknown
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
2026-01-04 12:42:41 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-01-04 12:42:43 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 5.953 seconds (process running for 2830.596)
|
||||
2026-01-04 12:42:52 INFO [Thread-19] com.zaxxer.hikari.HikariDataSource - HikariPool-5 - Shutdown initiated...
|
||||
2026-01-04 12:42:52 INFO [Thread-19] com.zaxxer.hikari.HikariDataSource - HikariPool-5 - Shutdown completed.
|
||||
2026-01-04 12:42:52 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.9 with PID 8855 (/home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros/target/classes started by jjimenez in /home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros)
|
||||
2026-01-04 12:42:52 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
|
||||
2026-01-04 12:42:53 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-6 - Starting...
|
||||
2026-01-04 12:42:53 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-6 - Added connection com.mysql.cj.jdbc.ConnectionImpl@3357436e
|
||||
2026-01-04 12:42:53 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-6 - Start completed.
|
||||
2026-01-04 12:42:53 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 12:42:53 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
|
||||
2026-01-04 12:42:53 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 12:42:53 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
|
||||
2026-01-04 12:42:53 INFO [restartedMain] liquibase.util - Run: 0
|
||||
2026-01-04 12:42:53 INFO [restartedMain] liquibase.util - Previously run: 67
|
||||
2026-01-04 12:42:53 INFO [restartedMain] liquibase.util - Filtered out: 0
|
||||
2026-01-04 12:42:53 INFO [restartedMain] liquibase.util - -------------------------------
|
||||
2026-01-04 12:42:53 INFO [restartedMain] liquibase.util - Total change sets: 67
|
||||
2026-01-04 12:42:53 INFO [restartedMain] liquibase.util - Update summary generated
|
||||
2026-01-04 12:42:53 INFO [restartedMain] liquibase.command - Command execution complete
|
||||
2026-01-04 12:42:53 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
|
||||
2026-01-04 12:42:53 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
|
||||
2026-01-04 12:42:53 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.43
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: undefined/unknown
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
2026-01-04 12:42:54 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-01-04 12:42:56 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 4.143 seconds (process running for 2843.335)
|
||||
2026-01-04 12:43:12 INFO [Thread-23] com.zaxxer.hikari.HikariDataSource - HikariPool-6 - Shutdown initiated...
|
||||
2026-01-04 12:43:12 INFO [Thread-23] com.zaxxer.hikari.HikariDataSource - HikariPool-6 - Shutdown completed.
|
||||
2026-01-04 12:43:12 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.9 with PID 8855 (/home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros/target/classes started by jjimenez in /home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros)
|
||||
2026-01-04 12:43:12 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
|
||||
2026-01-04 12:43:13 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-7 - Starting...
|
||||
2026-01-04 12:43:13 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-7 - Added connection com.mysql.cj.jdbc.ConnectionImpl@71111f76
|
||||
2026-01-04 12:43:13 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-7 - Start completed.
|
||||
2026-01-04 12:43:13 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 12:43:13 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
|
||||
2026-01-04 12:43:13 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 12:43:13 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
|
||||
2026-01-04 12:43:13 INFO [restartedMain] liquibase.util - Run: 0
|
||||
2026-01-04 12:43:13 INFO [restartedMain] liquibase.util - Previously run: 67
|
||||
2026-01-04 12:43:13 INFO [restartedMain] liquibase.util - Filtered out: 0
|
||||
2026-01-04 12:43:13 INFO [restartedMain] liquibase.util - -------------------------------
|
||||
2026-01-04 12:43:13 INFO [restartedMain] liquibase.util - Total change sets: 67
|
||||
2026-01-04 12:43:13 INFO [restartedMain] liquibase.util - Update summary generated
|
||||
2026-01-04 12:43:13 INFO [restartedMain] liquibase.command - Command execution complete
|
||||
2026-01-04 12:43:13 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
|
||||
2026-01-04 12:43:13 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
|
||||
2026-01-04 12:43:13 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.43
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: undefined/unknown
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
2026-01-04 12:43:14 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-01-04 12:43:15 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 3.66 seconds (process running for 2862.799)
|
||||
2026-01-04 12:43:18 INFO [Thread-27] com.zaxxer.hikari.HikariDataSource - HikariPool-7 - Shutdown initiated...
|
||||
2026-01-04 12:43:18 INFO [Thread-27] com.zaxxer.hikari.HikariDataSource - HikariPool-7 - Shutdown completed.
|
||||
2026-01-04 12:43:19 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.9 with PID 8855 (/home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros/target/classes started by jjimenez in /home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros)
|
||||
2026-01-04 12:43:19 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
|
||||
2026-01-04 12:43:20 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-8 - Starting...
|
||||
2026-01-04 12:43:20 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-8 - Added connection com.mysql.cj.jdbc.ConnectionImpl@52a2a7b5
|
||||
2026-01-04 12:43:20 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-8 - Start completed.
|
||||
2026-01-04 12:43:20 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 12:43:20 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
|
||||
2026-01-04 12:43:20 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 12:43:20 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
|
||||
2026-01-04 12:43:20 INFO [restartedMain] liquibase.util - Run: 0
|
||||
2026-01-04 12:43:20 INFO [restartedMain] liquibase.util - Previously run: 67
|
||||
2026-01-04 12:43:20 INFO [restartedMain] liquibase.util - Filtered out: 0
|
||||
2026-01-04 12:43:20 INFO [restartedMain] liquibase.util - -------------------------------
|
||||
2026-01-04 12:43:20 INFO [restartedMain] liquibase.util - Total change sets: 67
|
||||
2026-01-04 12:43:20 INFO [restartedMain] liquibase.util - Update summary generated
|
||||
2026-01-04 12:43:20 INFO [restartedMain] liquibase.command - Command execution complete
|
||||
2026-01-04 12:43:20 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
|
||||
2026-01-04 12:43:20 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
|
||||
2026-01-04 12:43:20 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.43
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: undefined/unknown
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
2026-01-04 12:43: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-01-04 12:43:22 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 3.451 seconds (process running for 2869.446)
|
||||
2026-01-04 12:43:57 INFO [Thread-31] com.zaxxer.hikari.HikariDataSource - HikariPool-8 - Shutdown initiated...
|
||||
2026-01-04 12:43:57 INFO [Thread-31] com.zaxxer.hikari.HikariDataSource - HikariPool-8 - Shutdown completed.
|
||||
2026-01-04 12:43:57 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.9 with PID 8855 (/home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros/target/classes started by jjimenez in /home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros)
|
||||
2026-01-04 12:43:57 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
|
||||
2026-01-04 12:43:58 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-9 - Starting...
|
||||
2026-01-04 12:43:58 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-9 - Added connection com.mysql.cj.jdbc.ConnectionImpl@41c34242
|
||||
2026-01-04 12:43:58 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-9 - Start completed.
|
||||
2026-01-04 12:43:58 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 12:43:58 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
|
||||
2026-01-04 12:43:58 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 12:43:58 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
|
||||
2026-01-04 12:43:58 INFO [restartedMain] liquibase.util - Run: 0
|
||||
2026-01-04 12:43:58 INFO [restartedMain] liquibase.util - Previously run: 67
|
||||
2026-01-04 12:43:58 INFO [restartedMain] liquibase.util - Filtered out: 0
|
||||
2026-01-04 12:43:58 INFO [restartedMain] liquibase.util - -------------------------------
|
||||
2026-01-04 12:43:58 INFO [restartedMain] liquibase.util - Total change sets: 67
|
||||
2026-01-04 12:43:58 INFO [restartedMain] liquibase.util - Update summary generated
|
||||
2026-01-04 12:43:58 INFO [restartedMain] liquibase.command - Command execution complete
|
||||
2026-01-04 12:43:58 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
|
||||
2026-01-04 12:43:58 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
|
||||
2026-01-04 12:43:58 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.43
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: undefined/unknown
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
2026-01-04 12:43:59 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-01-04 12:44:00 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 3.254 seconds (process running for 2907.825)
|
||||
2026-01-04 12:44:15 INFO [Thread-35] com.zaxxer.hikari.HikariDataSource - HikariPool-9 - Shutdown initiated...
|
||||
2026-01-04 12:44:15 INFO [Thread-35] com.zaxxer.hikari.HikariDataSource - HikariPool-9 - Shutdown completed.
|
||||
2026-01-04 12:44:15 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.9 with PID 8855 (/home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros/target/classes started by jjimenez in /home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros)
|
||||
2026-01-04 12:44:15 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
|
||||
2026-01-04 12:44:16 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-10 - Starting...
|
||||
2026-01-04 12:44:16 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-10 - Added connection com.mysql.cj.jdbc.ConnectionImpl@7b53dea4
|
||||
2026-01-04 12:44:16 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-10 - Start completed.
|
||||
2026-01-04 12:44:16 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 12:44:16 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
|
||||
2026-01-04 12:44:16 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 12:44:16 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
|
||||
2026-01-04 12:44:16 INFO [restartedMain] liquibase.util - Run: 0
|
||||
2026-01-04 12:44:16 INFO [restartedMain] liquibase.util - Previously run: 67
|
||||
2026-01-04 12:44:16 INFO [restartedMain] liquibase.util - Filtered out: 0
|
||||
2026-01-04 12:44:16 INFO [restartedMain] liquibase.util - -------------------------------
|
||||
2026-01-04 12:44:16 INFO [restartedMain] liquibase.util - Total change sets: 67
|
||||
2026-01-04 12:44:16 INFO [restartedMain] liquibase.util - Update summary generated
|
||||
2026-01-04 12:44:16 INFO [restartedMain] liquibase.command - Command execution complete
|
||||
2026-01-04 12:44:16 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
|
||||
2026-01-04 12:44:16 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
|
||||
2026-01-04 12:44:16 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.43
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: undefined/unknown
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
2026-01-04 12:44:17 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-01-04 12:44:19 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 3.297 seconds (process running for 2925.979)
|
||||
2026-01-04 12:47:00 INFO [Thread-39] com.zaxxer.hikari.HikariDataSource - HikariPool-10 - Shutdown initiated...
|
||||
2026-01-04 12:47:00 INFO [Thread-39] com.zaxxer.hikari.HikariDataSource - HikariPool-10 - Shutdown completed.
|
||||
2026-01-04 12:47:00 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.9 with PID 8855 (/home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros/target/classes started by jjimenez in /home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros)
|
||||
2026-01-04 12:47:00 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
|
||||
2026-01-04 12:47:01 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-11 - Starting...
|
||||
2026-01-04 12:47:01 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-11 - Added connection com.mysql.cj.jdbc.ConnectionImpl@fd8b2d5
|
||||
2026-01-04 12:47:01 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-11 - Start completed.
|
||||
2026-01-04 12:47:01 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 12:47:01 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
|
||||
2026-01-04 12:47:01 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 12:47:01 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
|
||||
2026-01-04 12:47:01 INFO [restartedMain] liquibase.util - Run: 0
|
||||
2026-01-04 12:47:01 INFO [restartedMain] liquibase.util - Previously run: 67
|
||||
2026-01-04 12:47:01 INFO [restartedMain] liquibase.util - Filtered out: 0
|
||||
2026-01-04 12:47:01 INFO [restartedMain] liquibase.util - -------------------------------
|
||||
2026-01-04 12:47:01 INFO [restartedMain] liquibase.util - Total change sets: 67
|
||||
2026-01-04 12:47:01 INFO [restartedMain] liquibase.util - Update summary generated
|
||||
2026-01-04 12:47:01 INFO [restartedMain] liquibase.command - Command execution complete
|
||||
2026-01-04 12:47:01 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
|
||||
2026-01-04 12:47:01 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
|
||||
2026-01-04 12:47:01 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.43
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: undefined/unknown
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
2026-01-04 12:47:02 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-01-04 12:47:03 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 2.992 seconds (process running for 3090.737)
|
||||
2026-01-04 12:51:58 INFO [Thread-43] com.zaxxer.hikari.HikariDataSource - HikariPool-11 - Shutdown initiated...
|
||||
2026-01-04 12:51:58 INFO [Thread-43] com.zaxxer.hikari.HikariDataSource - HikariPool-11 - Shutdown completed.
|
||||
2026-01-04 12:51:58 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.9 with PID 8855 (/home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros/target/classes started by jjimenez in /home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros)
|
||||
2026-01-04 12:51:58 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
|
||||
2026-01-04 12:51:59 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-12 - Starting...
|
||||
2026-01-04 12:51:59 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-12 - Added connection com.mysql.cj.jdbc.ConnectionImpl@2ee41125
|
||||
2026-01-04 12:51:59 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-12 - Start completed.
|
||||
2026-01-04 12:52:00 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 12:52:00 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
|
||||
2026-01-04 12:52:00 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 12:52:00 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
|
||||
2026-01-04 12:52:00 INFO [restartedMain] liquibase.util - Run: 0
|
||||
2026-01-04 12:52:00 INFO [restartedMain] liquibase.util - Previously run: 67
|
||||
2026-01-04 12:52:00 INFO [restartedMain] liquibase.util - Filtered out: 0
|
||||
2026-01-04 12:52:00 INFO [restartedMain] liquibase.util - -------------------------------
|
||||
2026-01-04 12:52:00 INFO [restartedMain] liquibase.util - Total change sets: 67
|
||||
2026-01-04 12:52:00 INFO [restartedMain] liquibase.util - Update summary generated
|
||||
2026-01-04 12:52:00 INFO [restartedMain] liquibase.command - Command execution complete
|
||||
2026-01-04 12:52:00 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
|
||||
2026-01-04 12:52:00 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
|
||||
2026-01-04 12:52:00 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.43
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: undefined/unknown
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
2026-01-04 12:52: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-01-04 12:52:02 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 3.118 seconds (process running for 3388.988)
|
||||
2026-01-04 13:04:32 INFO [Thread-47] com.zaxxer.hikari.HikariDataSource - HikariPool-12 - Shutdown initiated...
|
||||
2026-01-04 13:04:32 INFO [Thread-47] com.zaxxer.hikari.HikariDataSource - HikariPool-12 - Shutdown completed.
|
||||
2026-01-04 13:04:33 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.9 with PID 8855 (/home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros/target/classes started by jjimenez in /home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros)
|
||||
2026-01-04 13:04:33 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
|
||||
2026-01-04 13:04:33 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-13 - Starting...
|
||||
2026-01-04 13:04:33 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-13 - Added connection com.mysql.cj.jdbc.ConnectionImpl@2e1222f0
|
||||
2026-01-04 13:04:33 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-13 - Start completed.
|
||||
2026-01-04 13:04:34 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 13:04:34 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
|
||||
2026-01-04 13:04:34 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 13:04:34 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
|
||||
2026-01-04 13:04:34 INFO [restartedMain] liquibase.util - Run: 0
|
||||
2026-01-04 13:04:34 INFO [restartedMain] liquibase.util - Previously run: 67
|
||||
2026-01-04 13:04:34 INFO [restartedMain] liquibase.util - Filtered out: 0
|
||||
2026-01-04 13:04:34 INFO [restartedMain] liquibase.util - -------------------------------
|
||||
2026-01-04 13:04:34 INFO [restartedMain] liquibase.util - Total change sets: 67
|
||||
2026-01-04 13:04:34 INFO [restartedMain] liquibase.util - Update summary generated
|
||||
2026-01-04 13:04:34 INFO [restartedMain] liquibase.command - Command execution complete
|
||||
2026-01-04 13:04:34 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
|
||||
2026-01-04 13:04:34 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
|
||||
2026-01-04 13:04:34 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.43
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: undefined/unknown
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
2026-01-04 13:04:34 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-01-04 13:04:36 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 2.932 seconds (process running for 4142.969)
|
||||
2026-01-04 13:04:43 INFO [Thread-51] com.zaxxer.hikari.HikariDataSource - HikariPool-13 - Shutdown initiated...
|
||||
2026-01-04 13:04:43 INFO [Thread-51] com.zaxxer.hikari.HikariDataSource - HikariPool-13 - Shutdown completed.
|
||||
2026-01-04 13:04:43 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.9 with PID 8855 (/home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros/target/classes started by jjimenez in /home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros)
|
||||
2026-01-04 13:04:43 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
|
||||
2026-01-04 13:04:44 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-14 - Starting...
|
||||
2026-01-04 13:04:44 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-14 - Added connection com.mysql.cj.jdbc.ConnectionImpl@54ac41f3
|
||||
2026-01-04 13:04:44 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-14 - Start completed.
|
||||
2026-01-04 13:04:45 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 13:04:45 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
|
||||
2026-01-04 13:04:45 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 13:04:45 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
|
||||
2026-01-04 13:04:45 INFO [restartedMain] liquibase.util - Run: 0
|
||||
2026-01-04 13:04:45 INFO [restartedMain] liquibase.util - Previously run: 67
|
||||
2026-01-04 13:04:45 INFO [restartedMain] liquibase.util - Filtered out: 0
|
||||
2026-01-04 13:04:45 INFO [restartedMain] liquibase.util - -------------------------------
|
||||
2026-01-04 13:04:45 INFO [restartedMain] liquibase.util - Total change sets: 67
|
||||
2026-01-04 13:04:45 INFO [restartedMain] liquibase.util - Update summary generated
|
||||
2026-01-04 13:04:45 INFO [restartedMain] liquibase.command - Command execution complete
|
||||
2026-01-04 13:04:45 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
|
||||
2026-01-04 13:04:45 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
|
||||
2026-01-04 13:04:45 INFO [restartedMain] o.hibernate.orm.connections.pooling - HHH10001005: Database info:
|
||||
Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-14)']
|
||||
Database driver: undefined/unknown
|
||||
Database version: 8.0.43
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: undefined/unknown
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
2026-01-04 13:04:45 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-01-04 13:04:47 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 3.138 seconds (process running for 4154.036)
|
||||
2026-01-04 13:04:48 INFO [Thread-55] com.zaxxer.hikari.HikariDataSource - HikariPool-14 - Shutdown initiated...
|
||||
2026-01-04 13:04:48 INFO [Thread-55] com.zaxxer.hikari.HikariDataSource - HikariPool-14 - Shutdown completed.
|
||||
2026-01-04 13:04:49 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.9 with PID 8855 (/home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros/target/classes started by jjimenez in /home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros)
|
||||
2026-01-04 13:04:49 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
|
||||
2026-01-04 13:04:49 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-15 - Starting...
|
||||
2026-01-04 13:04:49 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-15 - Added connection com.mysql.cj.jdbc.ConnectionImpl@a47dda0
|
||||
2026-01-04 13:04:49 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-15 - Start completed.
|
||||
2026-01-04 13:04:49 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 13:04:50 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
|
||||
2026-01-04 13:04:50 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 13:04:50 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
|
||||
2026-01-04 13:04:50 INFO [restartedMain] liquibase.util - Run: 0
|
||||
2026-01-04 13:04:50 INFO [restartedMain] liquibase.util - Previously run: 67
|
||||
2026-01-04 13:04:50 INFO [restartedMain] liquibase.util - Filtered out: 0
|
||||
2026-01-04 13:04:50 INFO [restartedMain] liquibase.util - -------------------------------
|
||||
2026-01-04 13:04:50 INFO [restartedMain] liquibase.util - Total change sets: 67
|
||||
2026-01-04 13:04:50 INFO [restartedMain] liquibase.util - Update summary generated
|
||||
2026-01-04 13:04:50 INFO [restartedMain] liquibase.command - Command execution complete
|
||||
2026-01-04 13:04:50 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
|
||||
2026-01-04 13:04:50 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
|
||||
2026-01-04 13:04:50 INFO [restartedMain] o.hibernate.orm.connections.pooling - HHH10001005: Database info:
|
||||
Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-15)']
|
||||
Database driver: undefined/unknown
|
||||
Database version: 8.0.43
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: undefined/unknown
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
2026-01-04 13:04:50 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-01-04 13:04:51 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 2.79 seconds (process running for 4158.744)
|
||||
2026-01-04 13:05:12 INFO [Thread-59] com.zaxxer.hikari.HikariDataSource - HikariPool-15 - Shutdown initiated...
|
||||
2026-01-04 13:05:12 INFO [Thread-59] com.zaxxer.hikari.HikariDataSource - HikariPool-15 - Shutdown completed.
|
||||
2026-01-04 13:05:13 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.9 with PID 8855 (/home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros/target/classes started by jjimenez in /home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros)
|
||||
2026-01-04 13:05:13 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
|
||||
2026-01-04 13:05:13 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-16 - Starting...
|
||||
2026-01-04 13:05:13 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-16 - Added connection com.mysql.cj.jdbc.ConnectionImpl@79bf3891
|
||||
2026-01-04 13:05:13 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-16 - Start completed.
|
||||
2026-01-04 13:05:14 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 13:05:14 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
|
||||
2026-01-04 13:05:14 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 13:05:14 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
|
||||
2026-01-04 13:05:14 INFO [restartedMain] liquibase.util - Run: 0
|
||||
2026-01-04 13:05:14 INFO [restartedMain] liquibase.util - Previously run: 67
|
||||
2026-01-04 13:05:14 INFO [restartedMain] liquibase.util - Filtered out: 0
|
||||
2026-01-04 13:05:14 INFO [restartedMain] liquibase.util - -------------------------------
|
||||
2026-01-04 13:05:14 INFO [restartedMain] liquibase.util - Total change sets: 67
|
||||
2026-01-04 13:05:14 INFO [restartedMain] liquibase.util - Update summary generated
|
||||
2026-01-04 13:05:14 INFO [restartedMain] liquibase.command - Command execution complete
|
||||
2026-01-04 13:05:14 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
|
||||
2026-01-04 13:05:14 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
|
||||
2026-01-04 13:05:14 INFO [restartedMain] o.hibernate.orm.connections.pooling - HHH10001005: Database info:
|
||||
Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-16)']
|
||||
Database driver: undefined/unknown
|
||||
Database version: 8.0.43
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: undefined/unknown
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
2026-01-04 13:05:14 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-01-04 13:05:15 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 2.936 seconds (process running for 4182.923)
|
||||
2026-01-04 13:06:08 INFO [Thread-63] com.zaxxer.hikari.HikariDataSource - HikariPool-16 - Shutdown initiated...
|
||||
2026-01-04 13:06:08 INFO [Thread-63] com.zaxxer.hikari.HikariDataSource - HikariPool-16 - Shutdown completed.
|
||||
2026-01-04 13:06:08 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.9 with PID 8855 (/home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros/target/classes started by jjimenez in /home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros)
|
||||
2026-01-04 13:06:08 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
|
||||
2026-01-04 13:06:09 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-17 - Starting...
|
||||
2026-01-04 13:06:09 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-17 - Added connection com.mysql.cj.jdbc.ConnectionImpl@5a40f7e5
|
||||
2026-01-04 13:06:09 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-17 - Start completed.
|
||||
2026-01-04 13:06:09 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 13:06:09 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
|
||||
2026-01-04 13:06:09 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 13:06:09 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
|
||||
2026-01-04 13:06:09 INFO [restartedMain] liquibase.util - Run: 0
|
||||
2026-01-04 13:06:09 INFO [restartedMain] liquibase.util - Previously run: 67
|
||||
2026-01-04 13:06:09 INFO [restartedMain] liquibase.util - Filtered out: 0
|
||||
2026-01-04 13:06:09 INFO [restartedMain] liquibase.util - -------------------------------
|
||||
2026-01-04 13:06:09 INFO [restartedMain] liquibase.util - Total change sets: 67
|
||||
2026-01-04 13:06:09 INFO [restartedMain] liquibase.util - Update summary generated
|
||||
2026-01-04 13:06:09 INFO [restartedMain] liquibase.command - Command execution complete
|
||||
2026-01-04 13:06:09 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
|
||||
2026-01-04 13:06:09 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
|
||||
2026-01-04 13:06:09 INFO [restartedMain] o.hibernate.orm.connections.pooling - HHH10001005: Database info:
|
||||
Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-17)']
|
||||
Database driver: undefined/unknown
|
||||
Database version: 8.0.43
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: undefined/unknown
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
2026-01-04 13:06:10 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-01-04 13:06:11 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 2.647 seconds (process running for 4238.563)
|
||||
2026-01-04 13:06:14 INFO [Thread-67] com.zaxxer.hikari.HikariDataSource - HikariPool-17 - Shutdown initiated...
|
||||
2026-01-04 13:06:14 INFO [Thread-67] com.zaxxer.hikari.HikariDataSource - HikariPool-17 - Shutdown completed.
|
||||
2026-01-04 13:06:14 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.9 with PID 8855 (/home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros/target/classes started by jjimenez in /home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros)
|
||||
2026-01-04 13:06:14 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
|
||||
2026-01-04 13:06:15 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-18 - Starting...
|
||||
2026-01-04 13:06:15 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-18 - Added connection com.mysql.cj.jdbc.ConnectionImpl@38c04098
|
||||
2026-01-04 13:06:15 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-18 - Start completed.
|
||||
2026-01-04 13:06:15 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 13:06:15 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
|
||||
2026-01-04 13:06:15 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 13:06:15 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
|
||||
2026-01-04 13:06:15 INFO [restartedMain] liquibase.util - Run: 0
|
||||
2026-01-04 13:06:15 INFO [restartedMain] liquibase.util - Previously run: 67
|
||||
2026-01-04 13:06:15 INFO [restartedMain] liquibase.util - Filtered out: 0
|
||||
2026-01-04 13:06:15 INFO [restartedMain] liquibase.util - -------------------------------
|
||||
2026-01-04 13:06:15 INFO [restartedMain] liquibase.util - Total change sets: 67
|
||||
2026-01-04 13:06:15 INFO [restartedMain] liquibase.util - Update summary generated
|
||||
2026-01-04 13:06:15 INFO [restartedMain] liquibase.command - Command execution complete
|
||||
2026-01-04 13:06:15 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
|
||||
2026-01-04 13:06:15 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
|
||||
2026-01-04 13:06:15 INFO [restartedMain] o.hibernate.orm.connections.pooling - HHH10001005: Database info:
|
||||
Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-18)']
|
||||
Database driver: undefined/unknown
|
||||
Database version: 8.0.43
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: undefined/unknown
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
2026-01-04 13:06:16 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-01-04 13:06:17 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 2.738 seconds (process running for 4244.431)
|
||||
2026-01-04 13:06:27 INFO [Thread-71] com.zaxxer.hikari.HikariDataSource - HikariPool-18 - Shutdown initiated...
|
||||
2026-01-04 13:06:27 INFO [Thread-71] com.zaxxer.hikari.HikariDataSource - HikariPool-18 - Shutdown completed.
|
||||
2026-01-04 13:06:27 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.9 with PID 8855 (/home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros/target/classes started by jjimenez in /home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros)
|
||||
2026-01-04 13:06:27 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
|
||||
2026-01-04 13:06:28 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-19 - Starting...
|
||||
2026-01-04 13:06:28 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-19 - Added connection com.mysql.cj.jdbc.ConnectionImpl@7e1a5578
|
||||
2026-01-04 13:06:28 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-19 - Start completed.
|
||||
2026-01-04 13:06:28 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 13:06:28 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
|
||||
2026-01-04 13:06:28 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 13:06:28 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
|
||||
2026-01-04 13:06:28 INFO [restartedMain] liquibase.util - Run: 0
|
||||
2026-01-04 13:06:28 INFO [restartedMain] liquibase.util - Previously run: 67
|
||||
2026-01-04 13:06:28 INFO [restartedMain] liquibase.util - Filtered out: 0
|
||||
2026-01-04 13:06:28 INFO [restartedMain] liquibase.util - -------------------------------
|
||||
2026-01-04 13:06:28 INFO [restartedMain] liquibase.util - Total change sets: 67
|
||||
2026-01-04 13:06:28 INFO [restartedMain] liquibase.util - Update summary generated
|
||||
2026-01-04 13:06:28 INFO [restartedMain] liquibase.command - Command execution complete
|
||||
2026-01-04 13:06:28 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
|
||||
2026-01-04 13:06:28 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
|
||||
2026-01-04 13:06:28 INFO [restartedMain] o.hibernate.orm.connections.pooling - HHH10001005: Database info:
|
||||
Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-19)']
|
||||
Database driver: undefined/unknown
|
||||
Database version: 8.0.43
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: undefined/unknown
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
2026-01-04 13:06:29 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-01-04 13:06:30 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 2.765 seconds (process running for 4257.272)
|
||||
2026-01-04 13:06:32 INFO [Thread-75] com.zaxxer.hikari.HikariDataSource - HikariPool-19 - Shutdown initiated...
|
||||
2026-01-04 13:06:32 INFO [Thread-75] com.zaxxer.hikari.HikariDataSource - HikariPool-19 - Shutdown completed.
|
||||
2026-01-04 13:06:32 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.9 with PID 8855 (/home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros/target/classes started by jjimenez in /home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros)
|
||||
2026-01-04 13:06:32 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
|
||||
2026-01-04 13:06:33 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-20 - Starting...
|
||||
2026-01-04 13:06:33 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-20 - Added connection com.mysql.cj.jdbc.ConnectionImpl@6a1fc22f
|
||||
2026-01-04 13:06:33 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-20 - Start completed.
|
||||
2026-01-04 13:06:33 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 13:06:33 INFO [restartedMain] liquibase.lockservice - Successfully acquired change log lock
|
||||
2026-01-04 13:06:33 INFO [restartedMain] liquibase.command - Using deploymentId: 7528393385
|
||||
2026-01-04 13:06:33 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 13:06:33 INFO [restartedMain] liquibase.ui - Running Changeset: db/changelog/changesets/0024-series-facturacion-seeder.yml::0024-series-facturacion-seeder::jjo
|
||||
2026-01-04 13:06:33 INFO [restartedMain] liquibase.changelog - Custom SQL executed
|
||||
2026-01-04 13:06:33 WARN [restartedMain] liquibase.executor - 'VALUES function' is deprecated and will be removed in a future release. Please use an alias (INSERT INTO ... VALUES (...) AS alias) and replace VALUES(col) in the ON DUPLICATE KEY UPDATE clause with alias.col instead
|
||||
2026-01-04 13:06:33 INFO [restartedMain] liquibase.changelog - Custom SQL executed
|
||||
2026-01-04 13:06:33 WARN [restartedMain] liquibase.executor - 'VALUES function' is deprecated and will be removed in a future release. Please use an alias (INSERT INTO ... VALUES (...) AS alias) and replace VALUES(col) in the ON DUPLICATE KEY UPDATE clause with alias.col instead
|
||||
2026-01-04 13:06:33 INFO [restartedMain] liquibase.changelog - Custom SQL executed
|
||||
2026-01-04 13:06:33 INFO [restartedMain] liquibase.changelog - ChangeSet db/changelog/changesets/0024-series-facturacion-seeder.yml::0024-series-facturacion-seeder::jjo ran successfully in 496ms
|
||||
2026-01-04 13:06:33 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
|
||||
2026-01-04 13:06:33 INFO [restartedMain] liquibase.util - Run: 1
|
||||
2026-01-04 13:06:33 INFO [restartedMain] liquibase.util - Previously run: 67
|
||||
2026-01-04 13:06:33 INFO [restartedMain] liquibase.util - Filtered out: 0
|
||||
2026-01-04 13:06:33 INFO [restartedMain] liquibase.util - -------------------------------
|
||||
2026-01-04 13:06:33 INFO [restartedMain] liquibase.util - Total change sets: 68
|
||||
2026-01-04 13:06:33 INFO [restartedMain] liquibase.util - Update summary generated
|
||||
2026-01-04 13:06:33 INFO [restartedMain] liquibase.command - Update command completed successfully.
|
||||
2026-01-04 13:06:33 INFO [restartedMain] liquibase.ui - Liquibase: Update has been successful. Rows affected: 5
|
||||
2026-01-04 13:06:33 INFO [restartedMain] liquibase.lockservice - Successfully released change log lock
|
||||
2026-01-04 13:06:33 INFO [restartedMain] liquibase.command - Command execution complete
|
||||
2026-01-04 13:06:33 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
|
||||
2026-01-04 13:06:33 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
|
||||
2026-01-04 13:06:33 INFO [restartedMain] o.hibernate.orm.connections.pooling - HHH10001005: Database info:
|
||||
Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-20)']
|
||||
Database driver: undefined/unknown
|
||||
Database version: 8.0.43
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: undefined/unknown
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
2026-01-04 13:06:34 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-01-04 13:06:35 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 3.218 seconds (process running for 4262.44)
|
||||
2026-01-04 13:06:47 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.9 with PID 64681 (/home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros/target/classes started by jjimenez in /home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros)
|
||||
2026-01-04 13:06:47 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
|
||||
2026-01-04 13:06:51 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
|
||||
2026-01-04 13:06:51 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@2183ce6d
|
||||
2026-01-04 13:06:51 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
|
||||
2026-01-04 13:06:53 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 13:06:53 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
|
||||
2026-01-04 13:06:53 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 13:06:53 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
|
||||
2026-01-04 13:06:53 INFO [restartedMain] liquibase.util - Run: 0
|
||||
2026-01-04 13:06:53 INFO [restartedMain] liquibase.util - Previously run: 68
|
||||
2026-01-04 13:06:53 INFO [restartedMain] liquibase.util - Filtered out: 0
|
||||
2026-01-04 13:06:53 INFO [restartedMain] liquibase.util - -------------------------------
|
||||
2026-01-04 13:06:53 INFO [restartedMain] liquibase.util - Total change sets: 68
|
||||
2026-01-04 13:06:53 INFO [restartedMain] liquibase.util - Update summary generated
|
||||
2026-01-04 13:06:53 INFO [restartedMain] liquibase.command - Command execution complete
|
||||
2026-01-04 13:06:53 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
|
||||
2026-01-04 13:06:53 INFO [restartedMain] org.hibernate.Version - HHH000412: Hibernate ORM core version 6.6.39.Final
|
||||
2026-01-04 13:06:53 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
|
||||
2026-01-04 13:06:54 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.43
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: undefined/unknown
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
2026-01-04 13:06:56 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-01-04 13:07:01 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 15.348 seconds (process running for 16.728)
|
||||
2026-01-04 13:11:23 INFO [Thread-5] com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated...
|
||||
2026-01-04 13:11:23 INFO [Thread-5] com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed.
|
||||
2026-01-04 13:11:23 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.9 with PID 64681 (/home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros/target/classes started by jjimenez in /home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros)
|
||||
2026-01-04 13:11:23 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
|
||||
2026-01-04 13:11:24 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-2 - Starting...
|
||||
2026-01-04 13:11:24 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-2 - Added connection com.mysql.cj.jdbc.ConnectionImpl@3d01dc79
|
||||
2026-01-04 13:11:24 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-2 - Start completed.
|
||||
2026-01-04 13:11:25 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 13:11:25 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
|
||||
2026-01-04 13:11:25 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 13:11:25 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
|
||||
2026-01-04 13:11:25 INFO [restartedMain] liquibase.util - Run: 0
|
||||
2026-01-04 13:11:25 INFO [restartedMain] liquibase.util - Previously run: 68
|
||||
2026-01-04 13:11:25 INFO [restartedMain] liquibase.util - Filtered out: 0
|
||||
2026-01-04 13:11:25 INFO [restartedMain] liquibase.util - -------------------------------
|
||||
2026-01-04 13:11:25 INFO [restartedMain] liquibase.util - Total change sets: 68
|
||||
2026-01-04 13:11:25 INFO [restartedMain] liquibase.util - Update summary generated
|
||||
2026-01-04 13:11:25 INFO [restartedMain] liquibase.command - Command execution complete
|
||||
2026-01-04 13:11:25 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
|
||||
2026-01-04 13:11:25 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
|
||||
2026-01-04 13:11:25 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.43
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: undefined/unknown
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
2026-01-04 13:11:27 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-01-04 13:11:29 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 5.867 seconds (process running for 284.378)
|
||||
2026-01-04 13:11:31 INFO [Thread-7] com.zaxxer.hikari.HikariDataSource - HikariPool-2 - Shutdown initiated...
|
||||
2026-01-04 13:11:31 INFO [Thread-7] com.zaxxer.hikari.HikariDataSource - HikariPool-2 - Shutdown completed.
|
||||
2026-01-04 13:11:31 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Starting ErpApplication using Java 21.0.9 with PID 64681 (/home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros/target/classes started by jjimenez in /home/jjimenez/DEVELOPMENT/01_PROGRAMMING/erp-imprimelibros)
|
||||
2026-01-04 13:11:31 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - The following 1 profile is active: "dev"
|
||||
2026-01-04 13:11:32 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-3 - Starting...
|
||||
2026-01-04 13:11:32 INFO [restartedMain] com.zaxxer.hikari.pool.HikariPool - HikariPool-3 - Added connection com.mysql.cj.jdbc.ConnectionImpl@79744f71
|
||||
2026-01-04 13:11:32 INFO [restartedMain] com.zaxxer.hikari.HikariDataSource - HikariPool-3 - Start completed.
|
||||
2026-01-04 13:11:32 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 13:11:32 INFO [restartedMain] liquibase.ui - Database is up to date, no changesets to execute
|
||||
2026-01-04 13:11:32 INFO [restartedMain] liquibase.changelog - Reading from imprimelibros.DATABASECHANGELOG
|
||||
2026-01-04 13:11:32 INFO [restartedMain] liquibase.util - UPDATE SUMMARY
|
||||
2026-01-04 13:11:32 INFO [restartedMain] liquibase.util - Run: 0
|
||||
2026-01-04 13:11:32 INFO [restartedMain] liquibase.util - Previously run: 68
|
||||
2026-01-04 13:11:32 INFO [restartedMain] liquibase.util - Filtered out: 0
|
||||
2026-01-04 13:11:32 INFO [restartedMain] liquibase.util - -------------------------------
|
||||
2026-01-04 13:11:32 INFO [restartedMain] liquibase.util - Total change sets: 68
|
||||
2026-01-04 13:11:32 INFO [restartedMain] liquibase.util - Update summary generated
|
||||
2026-01-04 13:11:32 INFO [restartedMain] liquibase.command - Command execution complete
|
||||
2026-01-04 13:11:32 INFO [restartedMain] o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
|
||||
2026-01-04 13:11:32 INFO [restartedMain] o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
|
||||
2026-01-04 13:11:32 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.43
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: undefined/unknown
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
2026-01-04 13:11:33 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-01-04 13:11:34 INFO [restartedMain] c.imprimelibros.erp.ErpApplication - Started ErpApplication in 3.766 seconds (process running for 289.979)
|
||||
@ -149,6 +149,10 @@ public class SecurityConfig {
|
||||
"/pagos/redsys/**"
|
||||
)
|
||||
.permitAll()
|
||||
.requestMatchers("/impersonate/exit")
|
||||
.hasRole("PREVIOUS_ADMINISTRATOR")
|
||||
.requestMatchers("/impersonate")
|
||||
.hasAnyRole("SUPERADMIN", "ADMIN")
|
||||
.requestMatchers("/users/**").hasAnyRole("SUPERADMIN", "ADMIN")
|
||||
.anyRequest().authenticated())
|
||||
|
||||
|
||||
@ -398,13 +398,12 @@ public class skApiClient {
|
||||
public Map<String, Object> checkPedidoEstado(Long presupuestoId, Locale locale) {
|
||||
|
||||
try {
|
||||
|
||||
String jsonResponse = performWithRetry(() -> {
|
||||
String url = this.skApiUrl + "api/estado-pedido/" + presupuestoId;
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.setBearerAuth(authService.getToken()); // token actualizado
|
||||
headers.setBearerAuth(authService.getToken());
|
||||
headers.setAccept(java.util.List.of(MediaType.APPLICATION_JSON));
|
||||
|
||||
HttpEntity<Void> entity = new HttpEntity<>(headers);
|
||||
|
||||
@ -420,19 +419,34 @@ public class skApiClient {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode root = mapper.readTree(jsonResponse);
|
||||
|
||||
if (root.get("data") == null) {
|
||||
throw new RuntimeException(
|
||||
"Sin respuesta desde el servidor del proveedor");
|
||||
// ✅ Si falta data, devolvemos mapa sin "estado" (o con estado=null pero con
|
||||
// HashMap)
|
||||
if (root == null || root.get("data") == null || root.get("data").isNull()) {
|
||||
Map<String, Object> out = new HashMap<>();
|
||||
out.put("message", "Respuesta sin campo 'data' desde el servidor del proveedor");
|
||||
return out;
|
||||
}
|
||||
|
||||
String estado = root.get("data").asText();
|
||||
return Map.of(
|
||||
"estado", estado);
|
||||
return Map.of("estado", estado); // aquí NO es null, así que Map.of OK
|
||||
|
||||
} catch (HttpClientErrorException ex) {
|
||||
|
||||
if (ex.getStatusCode() == HttpStatus.NOT_FOUND) {
|
||||
// ✅ 404: devolvemos mapa sin "estado" para evitar null en Map.of
|
||||
Map<String, Object> out = new HashMap<>();
|
||||
out.put("notFound", true);
|
||||
out.put("message", "Orden de trabajo no encontrada para presupuestoId=" + presupuestoId);
|
||||
return out;
|
||||
}
|
||||
|
||||
throw ex;
|
||||
|
||||
} catch (JsonProcessingException e) {
|
||||
// Fallback al 80% del ancho
|
||||
return Map.of(
|
||||
"estado", null);
|
||||
// ✅ no parseable (HTML, debugbar, etc.)
|
||||
Map<String, Object> out = new HashMap<>();
|
||||
out.put("message", "Respuesta no-JSON o JSON inválido desde el proveedor");
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
@ -542,7 +556,7 @@ public class skApiClient {
|
||||
}
|
||||
|
||||
public Boolean aceptarFerro(Long presupuestoId, Locale locale) {
|
||||
|
||||
|
||||
String result = performWithRetry(() -> {
|
||||
String url = this.skApiUrl + "api/aceptar-ferro/" + presupuestoId;
|
||||
|
||||
@ -576,9 +590,8 @@ public class skApiClient {
|
||||
return Boolean.parseBoolean(result);
|
||||
}
|
||||
|
||||
|
||||
public Boolean cancelarPedido(Long pedidoId) {
|
||||
|
||||
|
||||
String result = performWithRetry(() -> {
|
||||
String url = this.skApiUrl + "api/cancelar-pedido/" + pedidoId;
|
||||
|
||||
@ -618,12 +631,21 @@ public class skApiClient {
|
||||
private String performWithRetry(Supplier<String> request) {
|
||||
try {
|
||||
return request.get();
|
||||
|
||||
} catch (HttpClientErrorException.Unauthorized e) {
|
||||
// Token expirado, renovar y reintentar
|
||||
authService.invalidateToken();
|
||||
|
||||
try {
|
||||
return request.get(); // segundo intento
|
||||
|
||||
} catch (HttpClientErrorException ex) {
|
||||
// ✅ IMPORTANTe: si el segundo intento es 404, NO lo envuelvas
|
||||
if (ex.getStatusCode() == HttpStatus.NOT_FOUND) {
|
||||
throw ex;
|
||||
}
|
||||
|
||||
// Si es otro 4xx/5xx, sí lo envolvemos
|
||||
throw new RuntimeException("La autenticación ha fallado tras renovar el token.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,6 +79,9 @@ public class Factura extends AbstractAuditedEntitySoftTs {
|
||||
@OneToMany(mappedBy = "factura", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
private List<FacturaPago> pagos = new ArrayList<>();
|
||||
|
||||
@OneToMany(mappedBy = "factura", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
private List<FacturaDireccion> direcciones = new ArrayList<>();
|
||||
|
||||
@Formula("(select u.fullname from users u where u.id = cliente_id)")
|
||||
private String clienteNombre;
|
||||
|
||||
@ -247,4 +250,22 @@ public class Factura extends AbstractAuditedEntitySoftTs {
|
||||
public void setPagos(List<FacturaPago> pagos) {
|
||||
this.pagos = pagos;
|
||||
}
|
||||
|
||||
public List<FacturaDireccion> getDirecciones() {
|
||||
return direcciones;
|
||||
}
|
||||
|
||||
public void setDirecciones(List<FacturaDireccion> direcciones) {
|
||||
this.direcciones = direcciones;
|
||||
}
|
||||
|
||||
public FacturaDireccion getDireccionFacturacion() {
|
||||
return (direcciones == null || direcciones.isEmpty()) ? null : direcciones.get(0);
|
||||
}
|
||||
|
||||
public void addDireccion(FacturaDireccion direccion) {
|
||||
direccion.setFactura(this);
|
||||
this.direcciones.add(direccion);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,209 @@
|
||||
package com.imprimelibros.erp.facturacion;
|
||||
|
||||
import com.imprimelibros.erp.direcciones.Direccion.TipoIdentificacionFiscal;
|
||||
import com.imprimelibros.erp.paises.Paises;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "facturas_direcciones",
|
||||
indexes = {
|
||||
@Index(name = "idx_facturas_direcciones_factura_id", columnList = "factura_id")
|
||||
}
|
||||
)
|
||||
public class FacturaDireccion {
|
||||
|
||||
@Column(name = "id")
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY, optional = false)
|
||||
@JoinColumn(name = "factura_id", nullable = false,
|
||||
foreignKey = @ForeignKey(name = "fk_facturas_direcciones_factura"))
|
||||
private Factura factura;
|
||||
|
||||
@Column(name = "unidades")
|
||||
private Integer unidades; // MEDIUMINT UNSIGNED
|
||||
|
||||
@Column(name = "email", length = 255)
|
||||
private String email;
|
||||
|
||||
@Column(name = "att", length = 150, nullable = false)
|
||||
private String att;
|
||||
|
||||
@Column(name = "direccion", length = 255, nullable = false)
|
||||
private String direccion;
|
||||
|
||||
@Column(name = "cp", nullable = false)
|
||||
private Integer cp; // MEDIUMINT UNSIGNED
|
||||
|
||||
@Column(name = "ciudad", length = 100, nullable = false)
|
||||
private String ciudad;
|
||||
|
||||
@Column(name = "provincia", length = 100, nullable = false)
|
||||
private String provincia;
|
||||
|
||||
@Column(name = "pais_code3", length = 3, nullable = false)
|
||||
private String paisCode3 = "esp";
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "pais_code3", referencedColumnName = "code3", insertable = false, updatable = false)
|
||||
private Paises pais;
|
||||
|
||||
@Column(name = "telefono", length = 30)
|
||||
private String telefono;
|
||||
|
||||
@Column(name = "instrucciones", length = 255)
|
||||
private String instrucciones;
|
||||
|
||||
@Column(name = "razon_social", length = 150)
|
||||
private String razonSocial;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "tipo_identificacion_fiscal", length = 20, nullable = false)
|
||||
private TipoIdentificacionFiscal tipoIdentificacionFiscal = TipoIdentificacionFiscal.DNI;
|
||||
|
||||
@Column(name = "identificacion_fiscal", length = 50)
|
||||
private String identificacionFiscal;
|
||||
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private java.time.Instant createdAt;
|
||||
|
||||
|
||||
// Getters / Setters
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Factura getFactura() {
|
||||
return factura;
|
||||
}
|
||||
|
||||
public void setFactura(Factura factura) {
|
||||
this.factura = factura;
|
||||
}
|
||||
|
||||
public Integer getUnidades() {
|
||||
return unidades;
|
||||
}
|
||||
|
||||
public void setUnidades(Integer unidades) {
|
||||
this.unidades = unidades;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getAtt() {
|
||||
return att;
|
||||
}
|
||||
|
||||
public void setAtt(String att) {
|
||||
this.att = att;
|
||||
}
|
||||
|
||||
public String getDireccion() {
|
||||
return direccion;
|
||||
}
|
||||
|
||||
public void setDireccion(String direccion) {
|
||||
this.direccion = direccion;
|
||||
}
|
||||
|
||||
public Integer getCp() {
|
||||
return cp;
|
||||
}
|
||||
|
||||
public void setCp(Integer cp) {
|
||||
this.cp = cp;
|
||||
}
|
||||
|
||||
public String getCiudad() {
|
||||
return ciudad;
|
||||
}
|
||||
|
||||
public void setCiudad(String ciudad) {
|
||||
this.ciudad = ciudad;
|
||||
}
|
||||
|
||||
public String getProvincia() {
|
||||
return provincia;
|
||||
}
|
||||
|
||||
public void setProvincia(String provincia) {
|
||||
this.provincia = provincia;
|
||||
}
|
||||
|
||||
public String getPaisCode3() {
|
||||
return paisCode3;
|
||||
}
|
||||
|
||||
public void setPaisCode3(String paisCode3) {
|
||||
this.paisCode3 = paisCode3;
|
||||
}
|
||||
|
||||
public Paises getPais() {
|
||||
return pais;
|
||||
}
|
||||
|
||||
public void setPais(Paises pais) {
|
||||
this.pais = pais;
|
||||
}
|
||||
|
||||
public String getTelefono() {
|
||||
return telefono;
|
||||
}
|
||||
|
||||
public void setTelefono(String telefono) {
|
||||
this.telefono = telefono;
|
||||
}
|
||||
|
||||
public String getInstrucciones() {
|
||||
return instrucciones;
|
||||
}
|
||||
|
||||
public void setInstrucciones(String instrucciones) {
|
||||
this.instrucciones = instrucciones;
|
||||
}
|
||||
|
||||
public String getRazonSocial() {
|
||||
return razonSocial;
|
||||
}
|
||||
|
||||
public void setRazonSocial(String razonSocial) {
|
||||
this.razonSocial = razonSocial;
|
||||
}
|
||||
|
||||
public TipoIdentificacionFiscal getTipoIdentificacionFiscal() {
|
||||
return tipoIdentificacionFiscal;
|
||||
}
|
||||
|
||||
public void setTipoIdentificacionFiscal(TipoIdentificacionFiscal tipoIdentificacionFiscal) {
|
||||
this.tipoIdentificacionFiscal = tipoIdentificacionFiscal;
|
||||
}
|
||||
|
||||
public String getIdentificacionFiscal() {
|
||||
return identificacionFiscal;
|
||||
}
|
||||
|
||||
public void setIdentificacionFiscal(String identificacionFiscal) {
|
||||
this.identificacionFiscal = identificacionFiscal;
|
||||
}
|
||||
|
||||
public java.time.Instant getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
public void setCreatedAt(java.time.Instant createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,15 @@
|
||||
package com.imprimelibros.erp.facturacion.controller;
|
||||
|
||||
import com.imprimelibros.erp.configurationERP.VariableService;
|
||||
import com.imprimelibros.erp.datatables.DataTable;
|
||||
import com.imprimelibros.erp.datatables.DataTablesParser;
|
||||
import com.imprimelibros.erp.datatables.DataTablesRequest;
|
||||
import com.imprimelibros.erp.datatables.DataTablesResponse;
|
||||
import com.imprimelibros.erp.direcciones.DireccionService;
|
||||
import com.imprimelibros.erp.facturacion.EstadoFactura;
|
||||
import com.imprimelibros.erp.facturacion.Factura;
|
||||
import com.imprimelibros.erp.facturacion.FacturaDireccion;
|
||||
import com.imprimelibros.erp.facturacion.dto.FacturaAddRequestDto;
|
||||
import com.imprimelibros.erp.facturacion.dto.FacturaGuardarDto;
|
||||
import com.imprimelibros.erp.facturacion.dto.FacturaLineaUpsertDto;
|
||||
import com.imprimelibros.erp.facturacion.dto.FacturaPagoUpsertDto;
|
||||
@ -23,6 +27,7 @@ import org.springframework.context.MessageSource;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@ -30,6 +35,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
import java.security.Principal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@ -45,17 +51,21 @@ public class FacturasController {
|
||||
private final TranslationService translationService;
|
||||
private final MessageSource messageSource;
|
||||
private final PedidoService pedidoService;
|
||||
private final VariableService variableService;
|
||||
private final DireccionService direccionService;
|
||||
|
||||
public FacturasController(
|
||||
FacturaRepository repo,
|
||||
TranslationService translationService,
|
||||
MessageSource messageSource,
|
||||
PedidoService pedidoService, FacturacionService facturacionService) {
|
||||
PedidoService pedidoService, FacturacionService facturacionService, VariableService variableService, DireccionService direccionService) {
|
||||
this.repo = repo;
|
||||
this.translationService = translationService;
|
||||
this.messageSource = messageSource;
|
||||
this.pedidoService = pedidoService;
|
||||
this.facturacionService = facturacionService;
|
||||
this.direccionService = direccionService;
|
||||
this.variableService = variableService;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
@ -73,14 +83,56 @@ public class FacturasController {
|
||||
return "imprimelibros/facturas/facturas-list";
|
||||
}
|
||||
|
||||
@GetMapping("/add")
|
||||
public String facturaAdd(Model model, Locale locale) {
|
||||
|
||||
List<String> keys = List.of(
|
||||
"facturas.form.cliente.placeholder",
|
||||
"facturas.add.form.validation.title",
|
||||
"facturas.add.form.validation",
|
||||
"facturas.error.create"
|
||||
);
|
||||
|
||||
Map<String, String> translations = translationService.getTranslations(locale, keys);
|
||||
model.addAttribute("languageBundle", translations);
|
||||
|
||||
model.addAttribute("defaultSerieRectificativa", variableService.getValorEntero("serie_facturacion_rect_default"));
|
||||
|
||||
return "imprimelibros/facturas/facturas-add-form";
|
||||
}
|
||||
|
||||
@PostMapping("/add")
|
||||
@ResponseBody
|
||||
public Map<String, Object> facturaAddPost(
|
||||
Model model,
|
||||
@RequestBody FacturaAddRequestDto request,
|
||||
Locale locale) {
|
||||
|
||||
Factura nuevaFactura = facturacionService.crearNuevaFactura(
|
||||
request.getUser(),
|
||||
request.getSerie(),
|
||||
request.getDireccion(),
|
||||
request.getFactura_rectificada()
|
||||
);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
if(nuevaFactura == null){
|
||||
result.put("success", false);
|
||||
result.put("message", messageSource.getMessage("facturas.error.create", null, "No se ha podido crear la factura. Revise los datos e inténtelo de nuevo.", locale));
|
||||
return result;
|
||||
}
|
||||
else{
|
||||
result.put("success", true);
|
||||
result.put("facturaId", nuevaFactura.getId());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public String facturaDetail(@PathVariable Long id, Model model, Locale locale) {
|
||||
Factura factura = repo.findById(id)
|
||||
.orElseThrow(() -> new EntityNotFoundException("Factura no encontrada con ID: " + id));
|
||||
|
||||
PedidoDireccion direccionFacturacion = pedidoService
|
||||
.getPedidoDireccionFacturacionByPedidoId(factura.getPedidoId());
|
||||
|
||||
List<String> keys = List.of(
|
||||
"facturas.lineas.error.base",
|
||||
"facturas.lineas.delete.title",
|
||||
@ -97,6 +149,8 @@ public class FacturasController {
|
||||
Map<String, String> translations = translationService.getTranslations(locale, keys);
|
||||
model.addAttribute("languageBundle", translations);
|
||||
|
||||
FacturaDireccion direccionFacturacion = factura.getDireccionFacturacion();
|
||||
|
||||
model.addAttribute("direccionFacturacion", direccionFacturacion);
|
||||
model.addAttribute("factura", factura);
|
||||
|
||||
@ -116,8 +170,8 @@ public class FacturasController {
|
||||
Factura factura = repo.findById(id)
|
||||
.orElseThrow(() -> new EntityNotFoundException("Factura no encontrada con ID: " + id));
|
||||
|
||||
PedidoDireccion direccionFacturacion = pedidoService
|
||||
.getPedidoDireccionFacturacionByPedidoId(factura.getPedidoId());
|
||||
FacturaDireccion direccionFacturacion = factura.getDireccionFacturacion();
|
||||
|
||||
|
||||
model.addAttribute("direccionFacturacion", direccionFacturacion);
|
||||
model.addAttribute("factura", factura);
|
||||
@ -134,7 +188,7 @@ public class FacturasController {
|
||||
return ResponseEntity.badRequest().body("Solo se pueden validar facturas en estado 'borrador'.");
|
||||
}
|
||||
|
||||
factura.setEstado(EstadoFactura.validada);
|
||||
facturacionService.validarFactura(factura.getId());
|
||||
repo.save(factura);
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
@ -178,6 +232,8 @@ public class FacturasController {
|
||||
return ResponseEntity.ok(Map.of("ok", true));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* -----------------------------
|
||||
* Pagos
|
||||
@ -296,4 +352,39 @@ public class FacturasController {
|
||||
.toJson(total);
|
||||
}
|
||||
|
||||
// -----------------------------
|
||||
// API: select2 Direcciones
|
||||
// -----------------------------
|
||||
@GetMapping("/api/get-direcciones")
|
||||
@ResponseBody
|
||||
public Map<String, Object> getSelect2Facturacion(
|
||||
@RequestParam(value = "q", required = false) String q1,
|
||||
@RequestParam(value = "term", required = false) String q2,
|
||||
@RequestParam(value = "user_id", required = true) Long userId,
|
||||
Authentication auth) {
|
||||
|
||||
|
||||
return direccionService.getForSelectFacturacion(q1, q2, userId);
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------
|
||||
// API: select2 facturas rectificables
|
||||
// -----------------------------
|
||||
@GetMapping("/api/get-facturas-rectificables")
|
||||
@ResponseBody
|
||||
public Map<String, Object> getSelect2FacturasRectificables(
|
||||
@RequestParam(value = "q", required = false) String q1,
|
||||
@RequestParam(value = "term", required = false) String q2,
|
||||
@RequestParam(value = "user_id", required = true) Long userId,
|
||||
Authentication auth) {
|
||||
try {
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return Map.of("results", List.of());
|
||||
}
|
||||
return facturacionService.getForSelectFacturasRectificables(q1, q2, userId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
package com.imprimelibros.erp.facturacion.dto;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
import com.imprimelibros.erp.facturacion.FacturaDireccion;
|
||||
import com.imprimelibros.erp.pedidos.PedidoDireccion;
|
||||
|
||||
public class DireccionFacturacionDto {
|
||||
@ -76,6 +79,13 @@ public class DireccionFacturacionDto {
|
||||
this.telefono = telefono;
|
||||
}
|
||||
|
||||
|
||||
public FacturaDireccion toFacturaDireccion() {
|
||||
FacturaDireccion fd = new FacturaDireccion();
|
||||
applyTo(fd);
|
||||
return fd;
|
||||
}
|
||||
|
||||
public PedidoDireccion toPedidoDireccion() {
|
||||
PedidoDireccion pd = new PedidoDireccion();
|
||||
applyTo(pd);
|
||||
@ -84,6 +94,7 @@ public class DireccionFacturacionDto {
|
||||
}
|
||||
|
||||
public void applyTo(PedidoDireccion pd) {
|
||||
pd.setAtt("");
|
||||
pd.setRazonSocial(this.razonSocial);
|
||||
pd.setIdentificacionFiscal(this.identificacionFiscal);
|
||||
pd.setDireccion(this.direccion);
|
||||
@ -107,4 +118,30 @@ public class DireccionFacturacionDto {
|
||||
pd.setTelefono(this.telefono);
|
||||
}
|
||||
|
||||
public void applyTo(FacturaDireccion fd ) {
|
||||
fd.setAtt("");
|
||||
fd.setRazonSocial(this.razonSocial);
|
||||
fd.setIdentificacionFiscal(this.identificacionFiscal);
|
||||
fd.setDireccion(this.direccion);
|
||||
|
||||
// CP robusto
|
||||
Integer cpInt = null;
|
||||
if (this.cp != null && !this.cp.isBlank()) {
|
||||
try {
|
||||
cpInt = Integer.valueOf(this.cp.trim());
|
||||
} catch (NumberFormatException ignored) {
|
||||
// si quieres, lanza IllegalArgumentException para validarlo
|
||||
}
|
||||
}
|
||||
fd.setCp(cpInt);
|
||||
|
||||
fd.setCiudad(this.ciudad);
|
||||
fd.setProvincia(this.provincia);
|
||||
|
||||
fd.setPaisCode3(this.paisKeyword);
|
||||
|
||||
fd.setTelefono(this.telefono);
|
||||
fd.setCreatedAt(Instant.now());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
package com.imprimelibros.erp.facturacion.dto;
|
||||
|
||||
public class FacturaAddRequestDto {
|
||||
|
||||
private Long user;
|
||||
private Long serie;
|
||||
private Long direccion;
|
||||
private Long factura_rectificada;
|
||||
|
||||
// getters y setters
|
||||
public Long getUser() {
|
||||
return user;
|
||||
}
|
||||
public void setUser(Long user) {
|
||||
this.user = user;
|
||||
}
|
||||
public Long getSerie() {
|
||||
return serie;
|
||||
}
|
||||
public void setSerie(Long serie) {
|
||||
this.serie = serie;
|
||||
}
|
||||
public Long getDireccion() {
|
||||
return direccion;
|
||||
}
|
||||
public void setDireccion(Long direccion) {
|
||||
this.direccion = direccion;
|
||||
}
|
||||
public Long getFactura_rectificada() {
|
||||
return factura_rectificada;
|
||||
}
|
||||
public void setFactura_rectificada(Long factura_rectificada) {
|
||||
this.factura_rectificada = factura_rectificada;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
package com.imprimelibros.erp.facturacion.dto;
|
||||
|
||||
import com.imprimelibros.erp.pedidos.PedidoDireccion;
|
||||
import com.imprimelibros.erp.facturacion.FacturaDireccion;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
import com.imprimelibros.erp.direcciones.Direccion.TipoIdentificacionFiscal;
|
||||
|
||||
public final class FacturaDireccionMapper {
|
||||
|
||||
private FacturaDireccionMapper() {}
|
||||
|
||||
public static FacturaDireccion fromPedidoDireccion(PedidoDireccion src) {
|
||||
if (src == null) return null;
|
||||
|
||||
FacturaDireccion dst = new FacturaDireccion();
|
||||
|
||||
dst.setUnidades(src.getUnidades());
|
||||
dst.setEmail(src.getEmail());
|
||||
dst.setAtt(src.getAtt());
|
||||
dst.setDireccion(src.getDireccion());
|
||||
dst.setCp(src.getCp());
|
||||
dst.setCiudad(src.getCiudad());
|
||||
dst.setProvincia(src.getProvincia());
|
||||
dst.setPaisCode3(src.getPaisCode3());
|
||||
dst.setTelefono(src.getTelefono());
|
||||
dst.setInstrucciones(src.getInstrucciones());
|
||||
dst.setRazonSocial(src.getRazonSocial());
|
||||
dst.setCreatedAt(Instant.now());
|
||||
|
||||
// OJO: en PedidoDireccion usas Direccion.TipoIdentificacionFiscal
|
||||
// En FacturaDireccion usa el enum que hayas definido/importado.
|
||||
dst.setTipoIdentificacionFiscal(
|
||||
TipoIdentificacionFiscal.valueOf(src.getTipoIdentificacionFiscal().name())
|
||||
);
|
||||
|
||||
dst.setIdentificacionFiscal(src.getIdentificacionFiscal());
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
public static FacturaDireccion fromDireccion(com.imprimelibros.erp.direcciones.Direccion src) {
|
||||
if (src == null) return null;
|
||||
|
||||
FacturaDireccion dst = new FacturaDireccion();
|
||||
|
||||
dst.setUnidades(null);
|
||||
dst.setEmail(src.getUser().getUserName());
|
||||
dst.setAtt(src.getAtt());
|
||||
dst.setDireccion(src.getDireccion());
|
||||
dst.setCp(src.getCp());
|
||||
dst.setCiudad(src.getCiudad());
|
||||
dst.setProvincia(src.getProvincia());
|
||||
dst.setPaisCode3(src.getPais().getCode3());
|
||||
dst.setTelefono(src.getTelefono());
|
||||
dst.setInstrucciones(src.getInstrucciones());
|
||||
dst.setRazonSocial(src.getRazonSocial());
|
||||
dst.setCreatedAt(Instant.now());
|
||||
|
||||
dst.setTipoIdentificacionFiscal(src.getTipoIdentificacionFiscal());
|
||||
|
||||
dst.setIdentificacionFiscal(src.getIdentificacionFiscal());
|
||||
|
||||
return dst;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package com.imprimelibros.erp.facturacion.repo;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import com.imprimelibros.erp.facturacion.FacturaDireccion;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface FacturaDireccionRepository extends JpaRepository<FacturaDireccion, Long> {
|
||||
|
||||
List<FacturaDireccion> findByFacturaId(Long facturaId);
|
||||
|
||||
Optional<FacturaDireccion> findFirstByFacturaIdOrderByIdAsc(Long facturaId);
|
||||
}
|
||||
@ -1,11 +1,21 @@
|
||||
package com.imprimelibros.erp.facturacion.repo;
|
||||
|
||||
import com.imprimelibros.erp.facturacion.EstadoFactura;
|
||||
import com.imprimelibros.erp.facturacion.EstadoPagoFactura;
|
||||
import com.imprimelibros.erp.facturacion.Factura;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface FacturaRepository extends JpaRepository<Factura, Long>, JpaSpecificationExecutor<Factura> {
|
||||
Optional<Factura> findByNumeroFactura(String numeroFactura);
|
||||
Factura findByPedidoId(Long pedidoId);
|
||||
List<Factura> findByClienteIdAndEstadoAndEstadoPagoAndSerieId(
|
||||
Long clienteId,
|
||||
EstadoFactura estado,
|
||||
EstadoPagoFactura estadoPago,
|
||||
Long serieId);
|
||||
|
||||
}
|
||||
|
||||
@ -3,20 +3,26 @@ package com.imprimelibros.erp.facturacion.service;
|
||||
import com.imprimelibros.erp.common.Utils;
|
||||
import com.imprimelibros.erp.configurationERP.VariableService;
|
||||
import com.imprimelibros.erp.facturacion.*;
|
||||
import com.imprimelibros.erp.facturacion.dto.DireccionFacturacionDto;
|
||||
import com.imprimelibros.erp.facturacion.dto.FacturaDireccionMapper;
|
||||
import com.imprimelibros.erp.facturacion.dto.FacturaGuardarDto;
|
||||
import com.imprimelibros.erp.facturacion.dto.FacturaLineaUpsertDto;
|
||||
import com.imprimelibros.erp.facturacion.dto.FacturaPagoUpsertDto;
|
||||
import com.imprimelibros.erp.facturacion.repo.FacturaDireccionRepository;
|
||||
import com.imprimelibros.erp.facturacion.repo.FacturaLineaRepository;
|
||||
import com.imprimelibros.erp.facturacion.repo.FacturaPagoRepository;
|
||||
import com.imprimelibros.erp.facturacion.repo.FacturaRepository;
|
||||
import com.imprimelibros.erp.facturacion.repo.SerieFacturaRepository;
|
||||
import com.imprimelibros.erp.pedidos.Pedido;
|
||||
import com.imprimelibros.erp.pedidos.PedidoDireccion;
|
||||
import com.imprimelibros.erp.pedidos.PedidoLinea;
|
||||
import com.imprimelibros.erp.pedidos.PedidoLineaRepository;
|
||||
import com.imprimelibros.erp.pedidos.PedidoService;
|
||||
import com.imprimelibros.erp.presupuesto.dto.Presupuesto;
|
||||
import com.imprimelibros.erp.users.User;
|
||||
import com.imprimelibros.erp.users.UserService;
|
||||
import com.imprimelibros.erp.direcciones.Direccion;
|
||||
import com.imprimelibros.erp.direcciones.DireccionRepository;
|
||||
|
||||
import jakarta.persistence.EntityNotFoundException;
|
||||
|
||||
@ -25,12 +31,17 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.Locale;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.security.Principal;
|
||||
import java.text.Collator;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
@ -42,6 +53,7 @@ public class FacturacionService {
|
||||
private final SerieFacturaRepository serieRepo;
|
||||
private final FacturaPagoRepository pagoRepo;
|
||||
private final FacturaLineaRepository lineaFacturaRepository;
|
||||
private final DireccionRepository direccionRepo;
|
||||
private final PedidoLineaRepository pedidoLineaRepo;
|
||||
private final UserService userService;
|
||||
private final Utils utils;
|
||||
@ -54,6 +66,7 @@ public class FacturacionService {
|
||||
FacturaLineaRepository lineaFacturaRepository,
|
||||
SerieFacturaRepository serieRepo,
|
||||
FacturaPagoRepository pagoRepo,
|
||||
DireccionRepository direccionRepo,
|
||||
PedidoLineaRepository pedidoLineaRepo,
|
||||
UserService userService,
|
||||
Utils utils,
|
||||
@ -64,6 +77,7 @@ public class FacturacionService {
|
||||
this.lineaFacturaRepository = lineaFacturaRepository;
|
||||
this.serieRepo = serieRepo;
|
||||
this.pagoRepo = pagoRepo;
|
||||
this.direccionRepo = direccionRepo;
|
||||
this.pedidoLineaRepo = pedidoLineaRepo;
|
||||
this.userService = userService;
|
||||
this.utils = utils;
|
||||
@ -87,6 +101,14 @@ public class FacturacionService {
|
||||
.orElseThrow(() -> new EntityNotFoundException("Factura no encontrada: " + facturaId));
|
||||
}
|
||||
|
||||
public Long getFacturaIdFromPedidoId(Long pedidoId) {
|
||||
Factura factura = facturaRepo.findByPedidoId(pedidoId);
|
||||
if (factura == null) {
|
||||
throw new EntityNotFoundException("Factura no encontrada para el pedido: " + pedidoId);
|
||||
}
|
||||
return factura.getId();
|
||||
}
|
||||
|
||||
// -----------------------
|
||||
// Nueva factura
|
||||
// -----------------------
|
||||
@ -147,6 +169,13 @@ public class FacturacionService {
|
||||
lineaEnvio.setFactura(factura);
|
||||
lineasFactura.add(lineaEnvio);
|
||||
}
|
||||
PedidoDireccion direccionPedido = pedidoService.getDireccionFacturacionPedido(pedido.getId());
|
||||
if(direccionPedido == null){
|
||||
throw new IllegalStateException("El pedido no tiene una dirección de facturación asociada.");
|
||||
}
|
||||
FacturaDireccion fd = FacturaDireccionMapper.fromPedidoDireccion(direccionPedido);
|
||||
|
||||
factura.addDireccion(fd);
|
||||
factura.setLineas(lineasFactura);
|
||||
|
||||
factura = facturaRepo.save(factura);
|
||||
@ -166,6 +195,46 @@ public class FacturacionService {
|
||||
return factura;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Factura crearNuevaFactura(Long userId, Long serieId, Long direccionId, Long facturaRectificadaId) {
|
||||
User cliente = userService.findById(userId);
|
||||
if (cliente == null) {
|
||||
throw new EntityNotFoundException("Cliente no encontrado: " + userId);
|
||||
}
|
||||
|
||||
SerieFactura serie = serieRepo.findById(serieId)
|
||||
.orElseThrow(() -> new EntityNotFoundException("Serie no encontrada: " + serieId));
|
||||
|
||||
Factura factura = new Factura();
|
||||
factura.setCliente(cliente);
|
||||
factura.setPedidoId(null);
|
||||
factura.setSerie(serie);
|
||||
factura.setEstado(EstadoFactura.borrador);
|
||||
factura.setEstadoPago(EstadoPagoFactura.pendiente);
|
||||
factura.setFechaEmision(LocalDateTime.now());
|
||||
factura.setCreatedAt(Instant.now());
|
||||
factura.setUpdatedAt(Instant.now());
|
||||
factura.setNumeroFactura(null);
|
||||
factura.setBaseImponible(BigDecimal.ZERO);
|
||||
factura.setIva4(BigDecimal.ZERO);
|
||||
factura.setIva21(BigDecimal.ZERO);
|
||||
factura.setTotalFactura(BigDecimal.ZERO);
|
||||
factura.setTotalPagado(BigDecimal.ZERO);
|
||||
factura.setLineas(new ArrayList<>());
|
||||
factura.setPagos(new ArrayList<>());
|
||||
Direccion direccion = direccionRepo.findById(direccionId)
|
||||
.orElseThrow(() -> new EntityNotFoundException("Dirección de factura no encontrada: " + direccionId));
|
||||
FacturaDireccion facturaDireccion = FacturaDireccionMapper.fromDireccion(direccion);
|
||||
factura.addDireccion(facturaDireccion);
|
||||
if(facturaRectificadaId != null){
|
||||
Factura facturaRectificada = facturaRepo.findById(facturaRectificadaId)
|
||||
.orElseThrow(() -> new EntityNotFoundException("Factura rectificada no encontrada: " + facturaRectificadaId));
|
||||
factura.setFacturaRectificativa(facturaRectificada);
|
||||
facturaRectificada.setFacturaRectificada(factura);
|
||||
}
|
||||
return facturaRepo.save(factura);
|
||||
}
|
||||
|
||||
// -----------------------
|
||||
// Estado / Numeración
|
||||
// -----------------------
|
||||
@ -225,6 +294,7 @@ public class FacturacionService {
|
||||
pedidoService.upsertDireccionFacturacion(pedidoId, dto.getDireccionFacturacion());
|
||||
|
||||
}
|
||||
upsertDireccionFacturacion(facturaId, dto.getDireccionFacturacion());
|
||||
|
||||
facturaRepo.save(factura);
|
||||
}
|
||||
@ -281,12 +351,79 @@ public class FacturacionService {
|
||||
return facturaRepo.save(factura);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Boolean upsertDireccionFacturacion(Long facturaId, DireccionFacturacionDto direccionData) {
|
||||
try {
|
||||
Factura factura = facturaRepo.findById(facturaId)
|
||||
.orElseThrow(() -> new EntityNotFoundException("Factura no encontrada: " + facturaId));
|
||||
|
||||
// ✅ Solo editable si borrador (tu regla actual para cabecera/dirección)
|
||||
if (factura.getEstado() != EstadoFactura.borrador) {
|
||||
throw new IllegalStateException("Solo se puede guardar dirección en borrador.");
|
||||
}
|
||||
|
||||
factura.getDirecciones().clear();
|
||||
factura.addDireccion(direccionData.toFacturaDireccion());
|
||||
facturaRepo.save(factura);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Object> getForSelectFacturasRectificables(String q1, String q2, Long userId) {
|
||||
try {
|
||||
String search = Optional.ofNullable(q1).orElse(q2);
|
||||
if (search != null) {
|
||||
search = search.trim();
|
||||
}
|
||||
final String q = (search == null || search.isEmpty())
|
||||
? null
|
||||
: search.toLowerCase();
|
||||
|
||||
List<Factura> all = facturaRepo.findByClienteIdAndEstadoAndEstadoPagoAndSerieId(
|
||||
userId,
|
||||
EstadoFactura.validada,
|
||||
EstadoPagoFactura.pagada,
|
||||
variableService.getValorEntero("serie_facturacion_default").longValue());
|
||||
|
||||
// Mapear a opciones id/text con i18n y filtrar por búsqueda si llega
|
||||
List<Map<String, String>> options = all.stream()
|
||||
.map(f -> {
|
||||
String id = f.getId().toString();
|
||||
String text = f.getNumeroFactura();
|
||||
Map<String, String> m = new HashMap<>();
|
||||
m.put("id", id); // lo normal en Select2: id = valor que guardarás (code3)
|
||||
m.put("text", text); // texto mostrado, i18n con fallback a keyword
|
||||
return m;
|
||||
})
|
||||
.filter(opt -> {
|
||||
if (q == null || q.isEmpty())
|
||||
return true;
|
||||
String text = opt.get("text").toLowerCase();
|
||||
return text.contains(q);
|
||||
})
|
||||
.sorted(Comparator.comparing(m -> m.get("text"), Collator.getInstance()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// Estructura Select2
|
||||
Map<String, Object> resp = new HashMap<>();
|
||||
resp.put("results", options);
|
||||
return resp;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return Map.of("results", List.of());
|
||||
}
|
||||
}
|
||||
|
||||
private String buildNumeroFactura(String prefijo, long numero) {
|
||||
String pref = (prefijo == null) ? "" : prefijo.trim();
|
||||
String num = String.format("%05d", numero);
|
||||
return pref.isBlank() ? num : (pref + " " + num + "/" + LocalDate.now().getYear());
|
||||
}
|
||||
|
||||
|
||||
// -----------------------
|
||||
// Líneas
|
||||
// -----------------------
|
||||
|
||||
@ -7,13 +7,18 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
import com.imprimelibros.erp.configurationERP.VariableService;
|
||||
import com.imprimelibros.erp.i18n.TranslationService;
|
||||
import com.imprimelibros.erp.pedidos.Pedido;
|
||||
import com.imprimelibros.erp.pedidos.PedidoRepository;
|
||||
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import com.imprimelibros.erp.common.Utils;
|
||||
|
||||
@Controller
|
||||
public class HomeController {
|
||||
@ -22,9 +27,10 @@ public class HomeController {
|
||||
private TranslationService translationService;
|
||||
@Autowired
|
||||
private VariableService variableService;
|
||||
@Autowired PedidoRepository pedidoRepository;
|
||||
|
||||
@GetMapping("/")
|
||||
public String index(Model model, Authentication authentication, Locale locale) {
|
||||
public String index(Model model, Authentication authentication, Principal principal,Locale locale) {
|
||||
|
||||
boolean isAuthenticated = authentication != null && authentication.isAuthenticated()
|
||||
&& !(authentication instanceof AnonymousAuthenticationToken);
|
||||
@ -37,7 +43,8 @@ public class HomeController {
|
||||
"presupuesto.impresion-cubierta",
|
||||
"presupuesto.impresion-cubierta-help",
|
||||
"presupuesto.iva-reducido",
|
||||
"presupuesto.iva-reducido-descripcion");
|
||||
"presupuesto.iva-reducido-descripcion",
|
||||
"pedido.gasto-anual");
|
||||
|
||||
Map<String, String> translations = translationService.getTranslations(locale, keys);
|
||||
model.addAttribute("languageBundle", translations);
|
||||
@ -51,6 +58,11 @@ public class HomeController {
|
||||
// empty translations for authenticated users
|
||||
Map<String, String> translations = Map.of();
|
||||
model.addAttribute("languageBundle", translations);
|
||||
|
||||
Instant haceUnAno = Instant.now().minusSeconds(365 * 24 * 60 * 60);
|
||||
Long userId = Utils.currentUserId(principal);
|
||||
double totalGastado = pedidoRepository.sumTotalByCreatedByAndCreatedAtAfter(userId, haceUnAno);
|
||||
model.addAttribute("totalGastado", totalGastado);
|
||||
}
|
||||
return "imprimelibros/home/home";
|
||||
}
|
||||
|
||||
@ -0,0 +1,72 @@
|
||||
package com.imprimelibros.erp.pedidos;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class PedidoEstadoService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(PedidoEstadoService.class);
|
||||
|
||||
private final PedidoLineaRepository pedidoLineaRepository;
|
||||
private final PedidoService pedidoService;
|
||||
|
||||
public PedidoEstadoService(PedidoLineaRepository pedidoLineaRepository, PedidoService pedidoService) {
|
||||
this.pedidoLineaRepository = pedidoLineaRepository;
|
||||
this.pedidoService = pedidoService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ejecuta cada noche a las 4:00 AM
|
||||
*/
|
||||
|
||||
@Transactional
|
||||
// test @Scheduled(cron = "0 * * * * *")
|
||||
@Scheduled(cron = "0 0 4 * * *")
|
||||
public void actualizarEstadosPedidos() {
|
||||
|
||||
log.info("JOB actualizarEstadosPedidos iniciado");
|
||||
|
||||
List<PedidoLinea> pedidosLineas = pedidoLineaRepository.findPedidosLineasParaActualizarEstado();
|
||||
|
||||
log.info("Pedidos líneas a procesar: {}", pedidosLineas.size());
|
||||
|
||||
|
||||
for (PedidoLinea linea : pedidosLineas) {
|
||||
|
||||
log.info("Actualizando estado pedidoLineaId={}", linea.getId());
|
||||
|
||||
try {
|
||||
Map<String, Object> resultado = pedidoService.actualizarEstado(linea.getId(), Locale.getDefault());
|
||||
|
||||
if (!Boolean.TRUE.equals(resultado.get("success"))) {
|
||||
log.error("Error al actualizar estado. pedidoLineaId={} message={}",
|
||||
linea.getId(), resultado.get("message"));
|
||||
} else {
|
||||
String msg = String.valueOf(resultado.get("message"));
|
||||
if (msg != null && msg.contains("Orden de trabajo no encontrada")) {
|
||||
log.warn("OT no encontrada. pedidoLineaId={} message={}", linea.getId(), msg);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
log.error("Excepción actualizando estado. pedidoLineaId={}", linea.getId(), ex);
|
||||
}
|
||||
|
||||
// rate limit / delay
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
log.error("Job interrumpido mientras dormía (rate limit).");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package com.imprimelibros.erp.pedidos;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
@ -9,7 +10,25 @@ import java.util.List;
|
||||
public interface PedidoLineaRepository extends JpaRepository<PedidoLinea, Long> {
|
||||
|
||||
List<PedidoLinea> findByPedidoId(Long pedidoId);
|
||||
|
||||
List<PedidoLinea> findByPedidoIdOrderByIdAsc(Long pedidoId);
|
||||
|
||||
List<PedidoLinea> findByPresupuestoId(Long presupuestoId);
|
||||
|
||||
@Query("""
|
||||
SELECT pl
|
||||
FROM PedidoLinea pl
|
||||
JOIN pl.presupuesto p
|
||||
WHERE pl.estadoManual = false
|
||||
AND pl.estado IN (
|
||||
'haciendo_ferro',
|
||||
'esperando_aceptacion_ferro',
|
||||
'produccion',
|
||||
'terminado'
|
||||
)
|
||||
AND p.proveedor = 'Safekat'
|
||||
AND p.proveedorRef1 IS NOT NULL
|
||||
AND p.proveedorRef2 IS NOT NULL
|
||||
""")
|
||||
List<PedidoLinea> findPedidosLineasParaActualizarEstado();
|
||||
}
|
||||
|
||||
@ -27,6 +27,9 @@ import com.imprimelibros.erp.externalApi.skApiClient;
|
||||
import com.imprimelibros.erp.facturacion.dto.DireccionFacturacionDto;
|
||||
import com.imprimelibros.erp.pedidos.PedidoLinea.Estado;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.client.HttpClientErrorException;
|
||||
|
||||
@Service
|
||||
public class PedidoService {
|
||||
|
||||
@ -191,24 +194,24 @@ public class PedidoService {
|
||||
|
||||
try {
|
||||
Pedido pedido = pedidoRepository.findById(pedidoId).orElse(null);
|
||||
if (pedido == null) {
|
||||
return false;
|
||||
if (pedido != null) {
|
||||
|
||||
PedidoDireccion direccionPedido = pedidoDireccionRepository.findByPedidoIdAndFacturacionTrue(pedidoId);
|
||||
|
||||
if (direccionPedido == null) {
|
||||
// crear
|
||||
direccionPedido = direccionData.toPedidoDireccion();
|
||||
direccionPedido.setPedido(pedido);
|
||||
|
||||
} else {
|
||||
// actualizar en la existente (NO crees una nueva, para conservar ID)
|
||||
direccionData.applyTo(direccionPedido); // si implementas applyTo()
|
||||
direccionPedido.setFacturacion(true); // por si acaso
|
||||
}
|
||||
|
||||
pedidoDireccionRepository.save(direccionPedido);
|
||||
}
|
||||
|
||||
PedidoDireccion direccionPedido = pedidoDireccionRepository.findByPedidoIdAndFacturacionTrue(pedidoId);
|
||||
|
||||
if (direccionPedido == null) {
|
||||
// crear
|
||||
direccionPedido = direccionData.toPedidoDireccion();
|
||||
direccionPedido.setPedido(pedido);
|
||||
|
||||
} else {
|
||||
// actualizar en la existente (NO crees una nueva, para conservar ID)
|
||||
direccionData.applyTo(direccionPedido); // si implementas applyTo()
|
||||
direccionPedido.setFacturacion(true); // por si acaso
|
||||
}
|
||||
|
||||
pedidoDireccionRepository.save(direccionPedido);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@ -299,43 +302,94 @@ public class PedidoService {
|
||||
}
|
||||
|
||||
public Map<String, Object> actualizarEstado(Long pedidoLineaId, Locale locale) {
|
||||
|
||||
PedidoLinea pedidoLinea = pedidoLineaRepository.findById(pedidoLineaId).orElse(null);
|
||||
if (pedidoLinea == null) {
|
||||
return Map.of("success", false,
|
||||
return Map.of(
|
||||
"success", false,
|
||||
"message", messageSource.getMessage("pedido.errors.linea-not-found", null, locale));
|
||||
}
|
||||
|
||||
if (pedidoLinea.getEstado().getPriority() >= PedidoLinea.Estado.haciendo_ferro.getPriority() &&
|
||||
pedidoLinea.getEstado().getPriority() < PedidoLinea.Estado.enviado.getPriority()) {
|
||||
PedidoLinea.Estado estadoOld = pedidoLinea.getEstado();
|
||||
Map<String, Object> result = skApiClient.checkPedidoEstado(
|
||||
Long.valueOf(pedidoLinea.getPresupuesto().getProveedorRef2().toString()), locale);
|
||||
if (result == null || !result.containsKey("estado")) {
|
||||
return Map.of(
|
||||
"success", false,
|
||||
"message", messageSource.getMessage("pedido.errors.update-server-error", null, locale));
|
||||
}
|
||||
PedidoLinea.Estado estadoSk = PedidoLinea.Estado.valueOf((String) result.get("estado"));
|
||||
if (estadoOld == estadoSk) {
|
||||
return Map.of(
|
||||
"success", true,
|
||||
"state", messageSource.getMessage("pedido.estado." + estadoSk.name(), null, locale),
|
||||
"stateKey", estadoSk.name(),
|
||||
"message", messageSource.getMessage("pedido.success.same-estado", null, locale));
|
||||
}
|
||||
PedidoLinea.Estado estadoOld = pedidoLinea.getEstado();
|
||||
if (estadoOld == null) {
|
||||
return Map.of(
|
||||
"success", false,
|
||||
"message", messageSource.getMessage("pedido.errors.cannot-update", null, locale));
|
||||
}
|
||||
|
||||
pedidoLinea.setEstado(estadoSk);
|
||||
pedidoLineaRepository.save(pedidoLinea);
|
||||
// Rango: >= haciendo_ferro y < enviado
|
||||
if (estadoOld.getPriority() < PedidoLinea.Estado.haciendo_ferro.getPriority()
|
||||
|| estadoOld.getPriority() >= PedidoLinea.Estado.enviado.getPriority()) {
|
||||
return Map.of(
|
||||
"success", false,
|
||||
"message", messageSource.getMessage("pedido.errors.cannot-update", null, locale));
|
||||
}
|
||||
|
||||
var presupuesto = pedidoLinea.getPresupuesto();
|
||||
if (presupuesto == null || presupuesto.getProveedorRef2() == null) {
|
||||
return Map.of(
|
||||
"success", false,
|
||||
"message", messageSource.getMessage("pedido.errors.update-server-error", null, locale));
|
||||
}
|
||||
|
||||
Long refExterna;
|
||||
try {
|
||||
refExterna = Long.valueOf(presupuesto.getProveedorRef2().toString());
|
||||
} catch (Exception ex) {
|
||||
return Map.of(
|
||||
"success", false,
|
||||
"message", messageSource.getMessage("pedido.errors.update-server-error", null, locale));
|
||||
}
|
||||
|
||||
Map<String, Object> result = skApiClient.checkPedidoEstado(refExterna, locale);
|
||||
|
||||
if (result == null) {
|
||||
return Map.of(
|
||||
"success", false,
|
||||
"message", messageSource.getMessage("pedido.errors.update-server-error", null, locale));
|
||||
}
|
||||
|
||||
if (Boolean.TRUE.equals(result.get("notFound"))) {
|
||||
return Map.of(
|
||||
"success", true,
|
||||
"message", String.valueOf(result.getOrDefault("message", "OT no encontrada (404). Se omite.")));
|
||||
}
|
||||
|
||||
Object estadoObj = result.get("estado");
|
||||
if (estadoObj == null) {
|
||||
return Map.of(
|
||||
"success", false,
|
||||
"message", messageSource.getMessage("pedido.errors.update-server-error", null, locale));
|
||||
}
|
||||
|
||||
String estadoStr = String.valueOf(estadoObj);
|
||||
|
||||
PedidoLinea.Estado estadoSk;
|
||||
try {
|
||||
// si la API devuelve minúsculas tipo "produccion", esto funciona
|
||||
estadoSk = PedidoLinea.Estado.valueOf(estadoStr.trim().toLowerCase());
|
||||
} catch (Exception ex) {
|
||||
return Map.of(
|
||||
"success", false,
|
||||
"message", messageSource.getMessage("pedido.errors.update-server-error", null, locale));
|
||||
}
|
||||
|
||||
if (estadoOld == estadoSk) {
|
||||
return Map.of(
|
||||
"success", true,
|
||||
"state", messageSource.getMessage("pedido.estado." + estadoSk.name(), null, locale),
|
||||
"stateKey", estadoSk.name(),
|
||||
"message", messageSource.getMessage("pedido.success.estado-actualizado", null, locale));
|
||||
"message", messageSource.getMessage("pedido.success.same-estado", null, locale));
|
||||
}
|
||||
|
||||
pedidoLinea.setEstado(estadoSk);
|
||||
pedidoLineaRepository.save(pedidoLinea);
|
||||
|
||||
return Map.of(
|
||||
"success", false,
|
||||
"message", messageSource.getMessage("pedido.errors.cannot-update", null, locale));
|
||||
"success", true,
|
||||
"state", messageSource.getMessage("pedido.estado." + estadoSk.name(), null, locale),
|
||||
"stateKey", estadoSk.name(),
|
||||
"message", messageSource.getMessage("pedido.success.estado-actualizado", null, locale));
|
||||
}
|
||||
|
||||
public Boolean markPedidoAsMaquetacionDone(Long pedidoId) {
|
||||
|
||||
@ -26,6 +26,7 @@ import com.imprimelibros.erp.datatables.DataTable;
|
||||
import com.imprimelibros.erp.datatables.DataTablesParser;
|
||||
import com.imprimelibros.erp.datatables.DataTablesRequest;
|
||||
import com.imprimelibros.erp.datatables.DataTablesResponse;
|
||||
import com.imprimelibros.erp.facturacion.service.FacturacionService;
|
||||
import com.imprimelibros.erp.i18n.TranslationService;
|
||||
import com.imprimelibros.erp.paises.PaisesService;
|
||||
import com.imprimelibros.erp.presupuesto.service.PresupuestoService;
|
||||
@ -52,10 +53,12 @@ public class PedidosController {
|
||||
private final PedidoLineaRepository repoPedidoLinea;
|
||||
private final PaisesService paisesService;
|
||||
private final TranslationService translationService;
|
||||
private final FacturacionService facturacionService;
|
||||
|
||||
public PedidosController(PedidoRepository repoPedido, PedidoService pedidoService, UserDao repoUser,
|
||||
MessageSource messageSource, TranslationService translationService,
|
||||
PedidoLineaRepository repoPedidoLinea, PaisesService paisesService, PresupuestoService presupuestoService) {
|
||||
PedidoLineaRepository repoPedidoLinea, PaisesService paisesService,
|
||||
FacturacionService facturacionService, PresupuestoService presupuestoService) {
|
||||
this.repoPedido = repoPedido;
|
||||
this.pedidoService = pedidoService;
|
||||
this.repoUser = repoUser;
|
||||
@ -63,6 +66,7 @@ public class PedidosController {
|
||||
this.translationService = translationService;
|
||||
this.repoPedidoLinea = repoPedidoLinea;
|
||||
this.paisesService = paisesService;
|
||||
this.facturacionService = facturacionService;
|
||||
this.presupuestoService = presupuestoService;
|
||||
}
|
||||
|
||||
@ -236,6 +240,7 @@ public class PedidosController {
|
||||
model.addAttribute("direccionFacturacion", direccionFacturacion);
|
||||
|
||||
Boolean showCancel = false;
|
||||
Boolean showDownloadFactura = true;
|
||||
List<Map<String, Object>> lineas = pedidoService.getLineas(id, locale);
|
||||
for (Map<String, Object> linea : lineas) {
|
||||
|
||||
@ -243,6 +248,9 @@ public class PedidosController {
|
||||
((Number) linea.get("lineaId")).longValue()).orElse(null);
|
||||
if (pedidoLinea != null) {
|
||||
Map<String, Boolean> buttons = new HashMap<>();
|
||||
if (pedidoLinea.getEstado() != PedidoLinea.Estado.enviado) {
|
||||
showDownloadFactura = false;
|
||||
}
|
||||
if (pedidoLinea.getEstado().getPriority() >= PedidoLinea.Estado.esperando_aceptacion_ferro.getPriority()
|
||||
&& pedidoLinea.getEstado().getPriority() <= PedidoLinea.Estado.produccion.getPriority()) {
|
||||
|
||||
@ -263,8 +271,10 @@ public class PedidosController {
|
||||
linea.put("buttons", buttons);
|
||||
}
|
||||
|
||||
if(pedidoLinea.getEstado() != PedidoLinea.Estado.cancelado && pedidoLinea.getEstado() != PedidoLinea.Estado.terminado && pedidoLinea.getEstado() != PedidoLinea.Estado.enviado) {
|
||||
showCancel = true;
|
||||
if (pedidoLinea.getEstado() != PedidoLinea.Estado.cancelado
|
||||
&& pedidoLinea.getEstado() != PedidoLinea.Estado.terminado
|
||||
&& pedidoLinea.getEstado() != PedidoLinea.Estado.enviado) {
|
||||
showCancel = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -280,8 +290,16 @@ public class PedidosController {
|
||||
linea.put("direccionesEntrega", dirEntrega);
|
||||
|
||||
}
|
||||
Long facturaId = null;
|
||||
if (showDownloadFactura) {
|
||||
facturaId = facturacionService.getFacturaIdFromPedidoId(id);
|
||||
}
|
||||
model.addAttribute("lineas", lineas);
|
||||
model.addAttribute("showCancel", showCancel);
|
||||
model.addAttribute("showCancel", showCancel);
|
||||
if (showDownloadFactura && facturaId != null) {
|
||||
model.addAttribute("facturaId", facturaId);
|
||||
model.addAttribute("showDownloadFactura", showDownloadFactura);
|
||||
}
|
||||
model.addAttribute("id", id);
|
||||
return "imprimelibros/pedidos/pedidos-view";
|
||||
}
|
||||
|
||||
@ -14,6 +14,8 @@ import java.util.Optional;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@ -63,6 +65,8 @@ import jakarta.validation.Valid;
|
||||
@RequestMapping("/presupuesto")
|
||||
public class PresupuestoController {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(PresupuestoController.class);
|
||||
|
||||
private final PresupuestoRepository presupuestoRepository;
|
||||
|
||||
@Autowired
|
||||
@ -509,6 +513,102 @@ public class PresupuestoController {
|
||||
return ResponseEntity.ok(resumen);
|
||||
}
|
||||
|
||||
@PostMapping("/public/prepare-claim")
|
||||
public ResponseEntity<?> prepareClaim(
|
||||
@RequestBody Map<String, Object> body,
|
||||
HttpServletRequest request) {
|
||||
|
||||
Long presupuestoId = objectMapper.convertValue(body.get("presupuestoId"), Long.class);
|
||||
if (presupuestoId == null) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "missing presupuestoId"));
|
||||
}
|
||||
|
||||
Presupuesto p = presupuestoRepository.findById(presupuestoId).orElse(null);
|
||||
if (p == null) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||
.body(Map.of("message", "presupuesto not found"));
|
||||
}
|
||||
|
||||
if (p.getOrigen() != Presupuesto.Origen.publico) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "presupuesto not public"));
|
||||
}
|
||||
|
||||
request.getSession(true).setAttribute("presupuesto_claim_id", presupuestoId);
|
||||
return ResponseEntity.ok(Map.of("success", true));
|
||||
}
|
||||
|
||||
@GetMapping("/claim")
|
||||
@Transactional
|
||||
public String claimPresupuesto(
|
||||
HttpServletRequest request,
|
||||
Authentication authentication,
|
||||
RedirectAttributes redirectAttributes,
|
||||
Locale locale) {
|
||||
|
||||
Object attr = request.getSession(false) != null
|
||||
? request.getSession(false).getAttribute("presupuesto_claim_id")
|
||||
: null;
|
||||
|
||||
Long presupuestoId = null;
|
||||
if (attr instanceof Long) {
|
||||
presupuestoId = (Long) attr;
|
||||
} else if (attr != null) {
|
||||
try {
|
||||
presupuestoId = Long.valueOf(attr.toString());
|
||||
} catch (NumberFormatException ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
if (presupuestoId == null) {
|
||||
redirectAttributes.addFlashAttribute("errorMessage",
|
||||
messageSource.getMessage("presupuesto.errores.presupuesto-no-existe", new Object[] { 0 }, locale));
|
||||
return "redirect:/presupuesto";
|
||||
}
|
||||
|
||||
Presupuesto p = presupuestoRepository.findById(presupuestoId).orElse(null);
|
||||
if (p == null) {
|
||||
redirectAttributes.addFlashAttribute("errorMessage",
|
||||
messageSource.getMessage("presupuesto.errores.presupuesto-no-existe",
|
||||
new Object[] { presupuestoId }, locale));
|
||||
return "redirect:/presupuesto";
|
||||
}
|
||||
|
||||
if (p.getUser() != null && authentication != null) {
|
||||
Long currentUserId = null;
|
||||
if (authentication.getPrincipal() instanceof UserDetailsImpl udi) {
|
||||
currentUserId = udi.getId();
|
||||
} else {
|
||||
currentUserId = userRepo.findIdByUserNameIgnoreCase(authentication.getName()).orElse(null);
|
||||
}
|
||||
if (currentUserId != null && p.getUser().getId().equals(currentUserId)) {
|
||||
request.getSession().removeAttribute("presupuesto_claim_id");
|
||||
return "redirect:/presupuesto/edit/" + p.getId();
|
||||
}
|
||||
}
|
||||
|
||||
if (p.getOrigen() != Presupuesto.Origen.publico) {
|
||||
redirectAttributes.addFlashAttribute("errorMessage",
|
||||
messageSource.getMessage("presupuesto.errores.presupuesto-no-existe",
|
||||
new Object[] { presupuestoId }, locale));
|
||||
return "redirect:/presupuesto";
|
||||
}
|
||||
|
||||
if (authentication != null) {
|
||||
if (authentication.getPrincipal() instanceof UserDetailsImpl udi) {
|
||||
p.setUser(userRepo.getReferenceById(udi.getId()));
|
||||
} else {
|
||||
userRepo.findByUserNameIgnoreCase(authentication.getName()).ifPresent(p::setUser);
|
||||
}
|
||||
}
|
||||
|
||||
p.setOrigen(Presupuesto.Origen.privado);
|
||||
p.setEstado(Presupuesto.Estado.borrador);
|
||||
presupuestoRepository.saveAndFlush(p);
|
||||
|
||||
request.getSession().removeAttribute("presupuesto_claim_id");
|
||||
return "redirect:/presupuesto/edit/" + p.getId();
|
||||
}
|
||||
|
||||
// =============================================
|
||||
// MÉTODOS PARA USUARIOS AUTENTICADOS
|
||||
// =============================================
|
||||
@ -824,6 +924,7 @@ public class PresupuestoController {
|
||||
return ResponseEntity.ok(Map.of("id", saveResult.get("presupuesto_id"),
|
||||
"message", messageSource.getMessage("presupuesto.exito.guardado", null, locale)));
|
||||
} catch (Exception ex) {
|
||||
log.error("Error al guardar el presupuesto", ex);
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body(Map.of("message",
|
||||
messageSource.getMessage("presupuesto.error.save-internal-error", null, locale),
|
||||
|
||||
@ -0,0 +1,115 @@
|
||||
package com.imprimelibros.erp.users;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
|
||||
import com.imprimelibros.erp.config.Sanitizer;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
|
||||
@Controller
|
||||
public class ImpersonationController {
|
||||
|
||||
private static final String PREVIOUS_ADMIN_ROLE = "ROLE_PREVIOUS_ADMINISTRATOR";
|
||||
private static final String SESSION_ATTR = "IMPERSONATOR_AUTH";
|
||||
|
||||
private final UserService userService;
|
||||
private final Sanitizer sanitizer;
|
||||
|
||||
public ImpersonationController(UserService userService, Sanitizer sanitizer) {
|
||||
this.userService = userService;
|
||||
this.sanitizer = sanitizer;
|
||||
}
|
||||
|
||||
@PostMapping("/impersonate")
|
||||
@PreAuthorize("hasRole('ADMIN') or hasRole('SUPERADMIN')")
|
||||
public ResponseEntity<Void> impersonate(
|
||||
@RequestParam("username") String username,
|
||||
Authentication authentication,
|
||||
HttpServletRequest request) {
|
||||
|
||||
if (authentication == null) {
|
||||
return ResponseEntity.status(401).build();
|
||||
}
|
||||
|
||||
if (hasRole(authentication, PREVIOUS_ADMIN_ROLE)) {
|
||||
return ResponseEntity.status(409).build();
|
||||
}
|
||||
|
||||
String normalized = sanitizer.plain(username);
|
||||
if (normalized == null || normalized.isBlank()) {
|
||||
return ResponseEntity.badRequest().build();
|
||||
}
|
||||
normalized = normalized.trim().toLowerCase();
|
||||
|
||||
if (authentication.getName() != null
|
||||
&& authentication.getName().equalsIgnoreCase(normalized)) {
|
||||
return ResponseEntity.status(409).build();
|
||||
}
|
||||
|
||||
UserDetails target;
|
||||
try {
|
||||
target = userService.loadUserByUsername(normalized);
|
||||
} catch (UsernameNotFoundException ex) {
|
||||
throw new AccessDeniedException("No autorizado");
|
||||
}
|
||||
|
||||
boolean targetIsSuperAdmin = target.getAuthorities().stream()
|
||||
.anyMatch(a -> "ROLE_SUPERADMIN".equals(a.getAuthority()));
|
||||
if (targetIsSuperAdmin) {
|
||||
throw new AccessDeniedException("No autorizado");
|
||||
}
|
||||
|
||||
HttpSession session = request.getSession(true);
|
||||
if (session.getAttribute(SESSION_ATTR) == null) {
|
||||
session.setAttribute(SESSION_ATTR, authentication);
|
||||
}
|
||||
|
||||
List<GrantedAuthority> authorities = new ArrayList<>(target.getAuthorities());
|
||||
authorities.add(new SimpleGrantedAuthority(PREVIOUS_ADMIN_ROLE));
|
||||
|
||||
UsernamePasswordAuthenticationToken newAuth = new UsernamePasswordAuthenticationToken(
|
||||
target, target.getPassword(), authorities);
|
||||
newAuth.setDetails(authentication.getDetails());
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(newAuth);
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
|
||||
@PostMapping("/impersonate/exit")
|
||||
@PreAuthorize("hasRole('PREVIOUS_ADMINISTRATOR')")
|
||||
public String exit(HttpServletRequest request) {
|
||||
HttpSession session = request.getSession(false);
|
||||
if (session != null) {
|
||||
Object previous = session.getAttribute(SESSION_ATTR);
|
||||
if (previous instanceof Authentication previousAuth) {
|
||||
SecurityContextHolder.getContext().setAuthentication(previousAuth);
|
||||
} else {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
session.removeAttribute(SESSION_ATTR);
|
||||
}
|
||||
return "redirect:/";
|
||||
}
|
||||
|
||||
private static boolean hasRole(Authentication auth, String role) {
|
||||
return auth != null
|
||||
&& auth.getAuthorities().stream()
|
||||
.anyMatch(a -> role.equals(a.getAuthority()));
|
||||
}
|
||||
}
|
||||
155
src/main/java/com/imprimelibros/erp/users/ProfileController.java
Normal file
155
src/main/java/com/imprimelibros/erp/users/ProfileController.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
@ -81,6 +81,9 @@ public class UserController {
|
||||
"usuarios.delete.button",
|
||||
"app.yes",
|
||||
"app.cancelar",
|
||||
"usuarios.impersonate.title",
|
||||
"usuarios.impersonate.text",
|
||||
"usuarios.impersonate.button",
|
||||
"usuarios.delete.ok.title",
|
||||
"usuarios.delete.ok.text");
|
||||
|
||||
@ -132,26 +135,36 @@ public class UserController {
|
||||
.collect(Collectors.joining(" ")))
|
||||
.add("actions", (user) -> {
|
||||
|
||||
boolean isSuperAdmin = authentication.getAuthorities().stream()
|
||||
boolean isSuperAdmin = authentication != null && authentication.getAuthorities().stream()
|
||||
.anyMatch(a -> a.getAuthority().equals("ROLE_SUPERADMIN"));
|
||||
|
||||
if (!isSuperAdmin) {
|
||||
return "<div class=\"hstack gap-3 flex-wrap\">\n" +
|
||||
" <a href=\"javascript:void(0);\" data-id=\"" + user.getId()
|
||||
+ "\" class=\"link-success btn-edit-user fs-15\"><i class=\"ri-edit-2-line\"></i></a>\n"
|
||||
+
|
||||
" </div>";
|
||||
} else {
|
||||
// Admin editando otro admin o usuario normal: puede editarse y eliminarse
|
||||
return "<div class=\"hstack gap-3 flex-wrap\">\n" +
|
||||
" <a href=\"javascript:void(0);\" data-id=\"" + user.getId()
|
||||
+ "\" class=\"link-success btn-edit-user fs-15\"><i class=\"ri-edit-2-line\"></i></a>\n"
|
||||
+
|
||||
" <a href=\"javascript:void(0);\" data-id=\"" + user.getId()
|
||||
+ "\" class=\"link-danger btn-delete-user fs-15\"><i class=\"user-delete ri-delete-bin-line\"></i></a>\n"
|
||||
+
|
||||
" </div>";
|
||||
boolean isSelf = authentication != null
|
||||
&& authentication.getName() != null
|
||||
&& authentication.getName().equalsIgnoreCase(user.getUserName());
|
||||
|
||||
boolean targetIsSuperAdmin = user.getRoles().stream()
|
||||
.anyMatch(r -> "SUPERADMIN".equalsIgnoreCase(r.getName()));
|
||||
|
||||
StringBuilder actions = new StringBuilder();
|
||||
actions.append("<div class=\"hstack gap-3 flex-wrap\">");
|
||||
actions.append("<a href=\"javascript:void(0);\" data-id=\"")
|
||||
.append(user.getId())
|
||||
.append("\" class=\"link-success btn-edit-user fs-15\"><i class=\"ri-edit-2-line\"></i></a>");
|
||||
|
||||
if (!isSelf && !targetIsSuperAdmin) {
|
||||
actions.append("<a href=\"javascript:void(0);\" data-username=\"")
|
||||
.append(user.getUserName())
|
||||
.append("\" class=\"link-info btn-impersonate-user fs-15\"><i class=\"ri-user-shared-line\"></i></a>");
|
||||
}
|
||||
|
||||
if (isSuperAdmin) {
|
||||
actions.append("<a href=\"javascript:void(0);\" data-id=\"")
|
||||
.append(user.getId())
|
||||
.append("\" class=\"link-danger btn-delete-user fs-15\"><i class=\"user-delete ri-delete-bin-line\"></i></a>");
|
||||
}
|
||||
|
||||
actions.append("</div>");
|
||||
return actions.toString();
|
||||
})
|
||||
.where(base)
|
||||
// Filtros custom:
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -33,7 +33,7 @@ logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{36} -
|
||||
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{36} - %msg%n
|
||||
|
||||
# Datos de la API de Safekat
|
||||
safekat.api.url=http://localhost:8000/
|
||||
safekat.api.url=https://erp-dev.safekat.es/
|
||||
safekat.api.email=imnavajas@coit.es
|
||||
safekat.api.password=Safekat2024
|
||||
|
||||
@ -41,6 +41,6 @@ safekat.api.password=Safekat2024
|
||||
redsys.environment=test
|
||||
redsys.url=https://sis-t.redsys.es:25443/sis/realizarPago
|
||||
redsys.refund.url=https://sis-t.redsys.es:25443/sis/rest/trataPeticionREST
|
||||
redsys.urls.ok=http://localhost:8080/pagos/redsys/ok
|
||||
redsys.urls.ko=http://localhost:8080/pagos/redsys/ko
|
||||
redsys.urls.notify=https://orological-sacrilegiously-lucille.ngrok-free.dev/pagos/redsys/notify
|
||||
redsys.urls.ok=https://imprimelibros.jjimenez.eu/pagos/redsys/ok
|
||||
redsys.urls.ko=https://imprimelibros.jjimenez.eu/pagos/redsys/ko
|
||||
redsys.urls.notify=https://imprimelibros.jjimenez.eu/pagos/redsys/notify
|
||||
46
src/main/resources/application-local.properties
Normal file
46
src/main/resources/application-local.properties
Normal file
@ -0,0 +1,46 @@
|
||||
# Profile desarrollo
|
||||
|
||||
#
|
||||
# Logging
|
||||
#
|
||||
logging.level.root=INFO
|
||||
logging.level.org.springframework.security=ERROR
|
||||
logging.level.org.springframework=ERROR
|
||||
logging.level.org.springframework.web=ERROR
|
||||
logging.level.org.thymeleaf=ERROR
|
||||
logging.level.org.apache.catalina.core=ERROR
|
||||
# Debug JPA / Hibernate
|
||||
#logging.level.org.hibernate.SQL=DEBUG
|
||||
#logging.level.org.hibernate.orm.jdbc.bind=TRACE
|
||||
#spring.jpa.properties.hibernate.format_sql=true
|
||||
|
||||
server.error.include-message=always
|
||||
server.error.include-stacktrace=on_param
|
||||
server.error.include-binding-errors=on_param
|
||||
|
||||
|
||||
# Archivo relativo a tu proyecto (asegúrate de que exista el directorio ./logs)
|
||||
logging.file.name=logs/erp.log
|
||||
|
||||
# Rotación tiempo+tamaño (mismo patrón, pero en ./logs)
|
||||
logging.logback.rollingpolicy.file-name-pattern=logs/erp-%d{yyyy-MM-dd}.%i.log
|
||||
logging.logback.rollingpolicy.max-file-size=10MB
|
||||
logging.logback.rollingpolicy.max-history=10
|
||||
logging.logback.rollingpolicy.total-size-cap=1GB
|
||||
|
||||
# Formatos con timestamp
|
||||
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{36} - %msg%n
|
||||
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{36} - %msg%n
|
||||
|
||||
# Datos de la API de Safekat
|
||||
safekat.api.url=http://localhost:8000/
|
||||
safekat.api.email=imnavajas@coit.es
|
||||
safekat.api.password=Safekat2024
|
||||
|
||||
# Configuración Redsys
|
||||
redsys.environment=test
|
||||
redsys.url=https://sis-t.redsys.es:25443/sis/realizarPago
|
||||
redsys.refund.url=https://sis-t.redsys.es:25443/sis/rest/trataPeticionREST
|
||||
redsys.urls.ok=http://localhost:8080/pagos/redsys/ok
|
||||
redsys.urls.ko=http://localhost:8080/pagos/redsys/ko
|
||||
redsys.urls.notify=https://orological-sacrilegiously-lucille.ngrok-free.dev/pagos/redsys/notify
|
||||
@ -18,6 +18,8 @@ server.error.include-binding-errors=never
|
||||
# Opcional: desactivar Whitelabel y servir tu propia página de error
|
||||
server.error.whitelabel.enabled=false
|
||||
|
||||
# Servelet options
|
||||
server.servlet.context-path=/intranet
|
||||
|
||||
# Archivo principal dentro del contenedor (monta /var/log/imprimelibros como volumen)
|
||||
logging.file.name=/var/log/imprimelibros/erp.log
|
||||
@ -42,6 +44,6 @@ safekat.api.password=Safekat2024
|
||||
redsys.environment=test
|
||||
redsys.url=https://sis-t.redsys.es:25443/sis/realizarPago
|
||||
redsys.refund.url=https://sis-t.redsys.es:25443/sis/rest/trataPeticionREST
|
||||
redsys.urls.ok=https://imprimelibros.jjimenez.eu/pagos/redsys/ok
|
||||
redsys.urls.ko=https://imprimelibros.jjimenez.eu/pagos/redsys/ko
|
||||
redsys.urls.notify=https://imprimelibros.jjimenez.eu/pagos/redsys/notify
|
||||
redsys.urls.ok=https://app.imprimelibros.com/intranet/pagos/redsys/ok
|
||||
redsys.urls.ko=https://app.imprimelibros.com/intranet/pagos/redsys/ko
|
||||
redsys.urls.notify=https://app.imprimelibros.com/intranet/pagos/redsys/notify
|
||||
@ -1,7 +1,8 @@
|
||||
spring.application.name=erp
|
||||
# Active profile
|
||||
spring.profiles.active=local
|
||||
#spring.profiles.active=dev
|
||||
spring.profiles.active=test
|
||||
#spring.profiles.active=test
|
||||
#spring.profiles.active=prod
|
||||
|
||||
|
||||
|
||||
@ -48,7 +48,7 @@ databaseChangeLog:
|
||||
sql: |
|
||||
INSERT INTO variables (clave, valor)
|
||||
SELECT
|
||||
'sere_facturacion_rect_default',
|
||||
'serie_facturacion_rect_default',
|
||||
CAST(sf.id AS CHAR)
|
||||
FROM series_facturas sf
|
||||
WHERE sf.prefijo = 'REC IL'
|
||||
|
||||
@ -0,0 +1,114 @@
|
||||
databaseChangeLog:
|
||||
- changeSet:
|
||||
id: create-facturas-direcciones
|
||||
author: jjo
|
||||
|
||||
changes:
|
||||
- createTable:
|
||||
tableName: facturas_direcciones
|
||||
columns:
|
||||
- column:
|
||||
name: id
|
||||
type: BIGINT
|
||||
autoIncrement: true
|
||||
constraints:
|
||||
primaryKey: true
|
||||
nullable: false
|
||||
|
||||
- column:
|
||||
name: factura_id
|
||||
type: BIGINT
|
||||
constraints:
|
||||
nullable: false
|
||||
|
||||
- column:
|
||||
name: unidades
|
||||
type: MEDIUMINT UNSIGNED
|
||||
|
||||
- column:
|
||||
name: email
|
||||
type: VARCHAR(255)
|
||||
|
||||
- column:
|
||||
name: att
|
||||
type: VARCHAR(150)
|
||||
constraints:
|
||||
nullable: false
|
||||
|
||||
- column:
|
||||
name: direccion
|
||||
type: VARCHAR(255)
|
||||
constraints:
|
||||
nullable: false
|
||||
|
||||
- column:
|
||||
name: cp
|
||||
type: MEDIUMINT UNSIGNED
|
||||
constraints:
|
||||
nullable: false
|
||||
|
||||
- column:
|
||||
name: ciudad
|
||||
type: VARCHAR(100)
|
||||
constraints:
|
||||
nullable: false
|
||||
|
||||
- column:
|
||||
name: provincia
|
||||
type: VARCHAR(100)
|
||||
constraints:
|
||||
nullable: false
|
||||
|
||||
- column:
|
||||
name: pais_code3
|
||||
type: CHAR(3)
|
||||
defaultValue: esp
|
||||
constraints:
|
||||
nullable: false
|
||||
|
||||
- column:
|
||||
name: telefono
|
||||
type: VARCHAR(30)
|
||||
|
||||
- column:
|
||||
name: instrucciones
|
||||
type: VARCHAR(255)
|
||||
|
||||
- column:
|
||||
name: razon_social
|
||||
type: VARCHAR(150)
|
||||
|
||||
- column:
|
||||
name: tipo_identificacion_fiscal
|
||||
type: ENUM('DNI','NIE','CIF','Pasaporte','VAT_ID')
|
||||
defaultValue: DNI
|
||||
constraints:
|
||||
nullable: false
|
||||
|
||||
- column:
|
||||
name: identificacion_fiscal
|
||||
type: VARCHAR(50)
|
||||
|
||||
- column:
|
||||
name: created_at
|
||||
type: TIMESTAMP
|
||||
defaultValueComputed: CURRENT_TIMESTAMP
|
||||
constraints:
|
||||
nullable: false
|
||||
|
||||
- addForeignKeyConstraint:
|
||||
constraintName: fk_facturas_direcciones_factura
|
||||
baseTableName: facturas_direcciones
|
||||
baseColumnNames: factura_id
|
||||
referencedTableName: facturas
|
||||
referencedColumnNames: id
|
||||
onDelete: CASCADE
|
||||
onUpdate: RESTRICT
|
||||
|
||||
rollback:
|
||||
- dropForeignKeyConstraint:
|
||||
baseTableName: facturas_direcciones
|
||||
constraintName: fk_facturas_direcciones_factura
|
||||
|
||||
- dropTable:
|
||||
tableName: facturas_direcciones
|
||||
@ -46,4 +46,6 @@ databaseChangeLog:
|
||||
- include:
|
||||
file: db/changelog/changesets/0023-facturacion.yml
|
||||
- include:
|
||||
file: db/changelog/changesets/0024-series-facturacion-seeder.yml
|
||||
file: db/changelog/changesets/0024-series-facturacion-seeder.yml
|
||||
- include:
|
||||
file: db/changelog/changesets/0025-create-facturas-direcciones.yml
|
||||
@ -6,4 +6,5 @@ app.cancelar=Cancel
|
||||
app.guardar=Save
|
||||
app.editar=Edit
|
||||
app.eliminar=Delete
|
||||
app.imprimir=Print
|
||||
app.imprimir=Print
|
||||
app.impersonate.exit=Return to my user
|
||||
|
||||
@ -32,4 +32,5 @@ app.sidebar.gestion-pagos=Gestión de Pagos
|
||||
|
||||
app.errors.403=No tienes permiso para acceder a esta página.
|
||||
|
||||
app.validation.required=Campo obligatorio
|
||||
app.validation.required=Campo obligatorio
|
||||
app.impersonate.exit=Volver a mi usuario
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
facturas.title=Facturas
|
||||
facturas.breadcrumb=Facturas
|
||||
facturas.breadcrumb.ver=Ver Factura
|
||||
facturas.breadcrumb.nueva=Nueva Factura
|
||||
|
||||
facturas.tabla.id=ID
|
||||
facturas.tabla.cliente=Cliente
|
||||
@ -19,10 +20,17 @@ facturas.estado.borrador=Borrador
|
||||
facturas.estado.validada=Validada
|
||||
|
||||
facturas.form.numero-factura=Número de Factura
|
||||
facturas.form.id=ID de la Factura
|
||||
facturas.form.factura-rectificada=Factura rectificada
|
||||
facturas.form.serie=Serie de facturación
|
||||
facturas.form.serie.placeholder=Seleccione una serie...
|
||||
facturas.form.fecha-emision=Fecha de Emisión
|
||||
facturas.form.cliente=Cliente
|
||||
facturas.form.direccion-facturacion=Dirección de Facturación
|
||||
facturas.form.direccion-facturacion.placeholder=Seleccione una dirección...
|
||||
facturas.form.cliente.placeholder=Seleccione un cliente...
|
||||
facturas.form.notas=Notas
|
||||
facturas.form.factura-rectificada=Factura rectificada
|
||||
|
||||
facturas.form.btn.validar=Validar Factura
|
||||
facturas.form.btn.borrador=Pasar a Borrador
|
||||
@ -85,3 +93,8 @@ facturas.delete.title=¿Estás seguro de que deseas eliminar esta factura?
|
||||
facturas.delete.text=Esta acción no se puede deshacer.
|
||||
facturas.delete.ok.title=Factura eliminada
|
||||
facturas.delete.ok.text=La factura ha sido eliminada correctamente.
|
||||
|
||||
facturas.add.form.validation.title=Error al crear la factura
|
||||
facturas.add.form.validation=Revise que todos los campos están rellenos
|
||||
|
||||
facturas.error.create=No se ha podido crear la factura. Revise los datos e inténtelo de nuevo.
|
||||
|
||||
@ -51,13 +51,17 @@ pedido.table.importe=Importe
|
||||
pedido.table.estado=Estado
|
||||
pedido.table.acciones=Acciones
|
||||
|
||||
pedido.gasto-anual=Gasto últimos 12 meses
|
||||
|
||||
pedido.view.tirada=Tirada
|
||||
pedido.view.view-presupuesto=Ver presupuesto
|
||||
pedido.view.aceptar-ferro=Aceptar ferro
|
||||
pedido.view.ferro-download=Descargar ferro
|
||||
pedido.view.cub-download=Descargar cubierta
|
||||
pedido.view.tapa-download=Descargar tapa
|
||||
pedido.view.descargar-factura=Descargar factura
|
||||
pedido.view.admin-actions=Acciones de administrador
|
||||
pedido.view.actions=Acciones
|
||||
pedido.view.cancel-title=¿Estás seguro de que deseas cancelar este pedido?
|
||||
pedido.view.cancel-text=Esta acción no se puede deshacer.
|
||||
|
||||
|
||||
@ -1 +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 <b>{0}</b>. You can return to your user from the menu.
|
||||
usuarios.impersonate.button=Continue
|
||||
usuarios.profile.title=Edit profile
|
||||
usuarios.profile.success=Profile updated successfully.
|
||||
|
||||
@ -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.
|
||||
@ -53,4 +59,9 @@ usuarios.delete.title=Eliminar usuario
|
||||
usuarios.delete.button=Si, ELIMINAR
|
||||
usuarios.delete.text=¿Está seguro de que desea eliminar al usuario?<br>Esta acción no se puede deshacer.
|
||||
usuarios.delete.ok.title=Usuario eliminado
|
||||
usuarios.delete.ok.text=El usuario ha sido eliminado con éxito.
|
||||
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 <b>{0}</b>. Podrás volver a tu usuario desde el menú.
|
||||
usuarios.impersonate.button=Entrar
|
||||
usuarios.profile.title=Editar perfil
|
||||
usuarios.profile.success=Perfil actualizado correctamente.
|
||||
|
||||
372
src/main/resources/static/assets/css/home.css
Normal file
372
src/main/resources/static/assets/css/home.css
Normal file
@ -0,0 +1,372 @@
|
||||
:root {
|
||||
/* ====== Colores (cámbialos a tu gusto) ====== */
|
||||
--banner-bg-1: #a5a091;
|
||||
--banner-bg-2: #8292a8;
|
||||
|
||||
--banner-panel-bg: #a1b1b2;
|
||||
--banner-panel-border: rgba(255, 255, 255, .75);
|
||||
|
||||
--text-main: #ffffff;
|
||||
--text-muted: rgba(255, 255, 255, .8);
|
||||
|
||||
--accent-1: #e5745b;
|
||||
/* salmón */
|
||||
--accent-2: #92b2a7;
|
||||
/* tu verde corporativo */
|
||||
--accent-3: #7cc7ff;
|
||||
/* toque azul claro */
|
||||
|
||||
--card-bg: #ffffff;
|
||||
--card-border: rgba(8, 42, 67, .18);
|
||||
--card-title: #0a314b;
|
||||
--card-chip-bg: var(--accent-1);
|
||||
--card-chip-text: #ffffff;
|
||||
|
||||
--shadow: 0 10px 30px rgba(0, 0, 0, .18);
|
||||
|
||||
/* ====== Medidas ====== */
|
||||
--radius-lg: 18px;
|
||||
--radius-md: 14px;
|
||||
--radius-sm: 10px;
|
||||
|
||||
--pad: 22px;
|
||||
}
|
||||
|
||||
.ib-loyalty-banner {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow);
|
||||
color: var(--text-main);
|
||||
|
||||
/* padding fluido */
|
||||
padding: clamp(14px, 2.2vw, 22px);
|
||||
|
||||
/* Importante: reserva espacio inferior para decoraciones (libro) en desktop */
|
||||
padding-bottom: clamp(18px, 3.2vw, 46px);
|
||||
|
||||
/* Fondo con gradiente + textura sutil */
|
||||
background:
|
||||
radial-gradient(1200px 500px at 20% 0%, rgba(124, 199, 255, .20), transparent 60%),
|
||||
radial-gradient(900px 450px at 90% 20%, rgba(243, 162, 133, .22), transparent 65%),
|
||||
linear-gradient(135deg, var(--banner-bg-1), var(--banner-bg-2));
|
||||
}
|
||||
|
||||
/* Opcional pero ayuda a que haya “lienzo” para el libro */
|
||||
@media (min-width: 1101px) {
|
||||
.ib-loyalty-banner {
|
||||
min-height: 240px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== Decoraciones generales ===== */
|
||||
.ib-loyalty-banner .decor {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
opacity: .95;
|
||||
}
|
||||
|
||||
/* Círculos/“sellos” */
|
||||
.ib-loyalty-banner .decor::before,
|
||||
.ib-loyalty-banner .decor::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 140px;
|
||||
height: 140px;
|
||||
border-radius: 50%;
|
||||
border: 10px solid rgba(243, 162, 133, .65);
|
||||
box-shadow: inset 0 0 0 10px rgba(255, 255, 255, .08);
|
||||
}
|
||||
|
||||
.ib-loyalty-banner .decor::before {
|
||||
top: -42px;
|
||||
right: -50px;
|
||||
transform: rotate(10deg);
|
||||
}
|
||||
|
||||
.ib-loyalty-banner .decor::after {
|
||||
bottom: -55px;
|
||||
left: -55px;
|
||||
border-color: rgba(243, 162, 133, .55);
|
||||
}
|
||||
|
||||
/* ===== Libros “dibujados” con SVG como background ===== */
|
||||
.ib-loyalty-banner .book {
|
||||
position: absolute;
|
||||
width: 190px;
|
||||
height: 150px;
|
||||
opacity: .9;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: contain;
|
||||
background-image: url("/assets/images/open-book.svg");
|
||||
|
||||
/* Sombra sin cargarte otros filtros */
|
||||
filter: drop-shadow(0 10px 18px rgba(0, 0, 0, .25));
|
||||
}
|
||||
|
||||
/* Libro pequeño: lo subimos un poco para que no se quede “bajo” cuando el layout crece */
|
||||
.ib-loyalty-banner .book.small {
|
||||
width: 150px;
|
||||
height: 120px;
|
||||
left: 22px;
|
||||
bottom: 18px;
|
||||
/* antes 10px */
|
||||
opacity: .85;
|
||||
z-index: 1;
|
||||
/* por encima del fondo, por debajo del contenido (contenido z-index 2) */
|
||||
}
|
||||
|
||||
/* ===== Contenido ===== */
|
||||
.ib-loyalty-inner {
|
||||
position: relative;
|
||||
display: grid;
|
||||
gap: clamp(12px, 2vw, 18px);
|
||||
|
||||
/* CLAVE: NO estires ambas columnas a la misma altura */
|
||||
align-items: start;
|
||||
|
||||
z-index: 2;
|
||||
|
||||
/* Dos columnas con mínimos reales */
|
||||
grid-template-columns: minmax(320px, 1.05fr) minmax(320px, .95fr);
|
||||
}
|
||||
|
||||
/* Apila antes para que no se estrangule */
|
||||
@media (max-width: 1100px) {
|
||||
.ib-loyalty-inner {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Panel principal (logo + textos) */
|
||||
.ib-loyalty-hero {
|
||||
border: 2px solid var(--banner-panel-border);
|
||||
border-radius: var(--radius-lg);
|
||||
background: var(--banner-panel-bg);
|
||||
padding: 18px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/*.ib-loyalty-hero::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: -2px;
|
||||
height: 6px;
|
||||
background: linear-gradient(90deg, transparent, var(--accent-1), transparent);
|
||||
opacity: .9;
|
||||
border-radius: 999px;
|
||||
}*/
|
||||
|
||||
.ib-loyalty-head {
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
/* responsive */
|
||||
}
|
||||
|
||||
.ib-loyalty-logo {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.ib-loyalty-logo img {
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.ib-loyalty-title {
|
||||
margin: 0;
|
||||
font-size: clamp(1.05rem, 1.2vw, 1.35rem);
|
||||
font-weight: 800;
|
||||
letter-spacing: .2px;
|
||||
}
|
||||
|
||||
.ib-loyalty-sub {
|
||||
margin: 4px 0 0 0;
|
||||
color: var(--text-muted);
|
||||
font-weight: 500;
|
||||
font-size: clamp(.9rem, 1vw, 1rem);
|
||||
}
|
||||
|
||||
/* ===== Rewards ===== */
|
||||
.ib-rewards {
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 14px 14px 10px;
|
||||
background: rgba(255, 255, 255, .04);
|
||||
border: 1px solid rgba(255, 255, 255, .12);
|
||||
}
|
||||
|
||||
.ib-rewards h6 {
|
||||
margin: 4px 6px 12px;
|
||||
font-size: .95rem;
|
||||
letter-spacing: .25px;
|
||||
opacity: .95;
|
||||
}
|
||||
|
||||
.ib-rewards-grid{
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
|
||||
/* Nunca más de 3 columnas, pero baja si no hay sitio */
|
||||
grid-template-columns: repeat(3, minmax(160px, 1fr));
|
||||
}
|
||||
|
||||
@media (max-width: 992px){
|
||||
.ib-rewards-grid{
|
||||
grid-template-columns: repeat(2, minmax(160px, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 520px){
|
||||
.ib-rewards-grid{
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.ib-card {
|
||||
background: var(--card-bg);
|
||||
border: 1px solid var(--card-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 10px 10px 9px;
|
||||
color: var(--card-title);
|
||||
box-shadow: 0 8px 18px rgba(0, 0, 0, .10);
|
||||
}
|
||||
|
||||
.ib-card .range {
|
||||
font-size: .82rem;
|
||||
opacity: .85;
|
||||
font-weight: 700;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.ib-card .percent {
|
||||
font-size: 1.35rem;
|
||||
font-weight: 900;
|
||||
line-height: 1;
|
||||
margin: 2px 0 8px;
|
||||
}
|
||||
|
||||
.ib-card .chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 5px 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--card-chip-bg);
|
||||
color: var(--card-chip-text);
|
||||
font-weight: 800;
|
||||
font-size: .78rem;
|
||||
letter-spacing: .2px;
|
||||
}
|
||||
|
||||
/* Tarjeta “0%” con borde punteado (si la usas) */
|
||||
.ib-card.is-empty {
|
||||
background: rgba(255, 255, 255, .9);
|
||||
border: 2px dashed rgba(10, 49, 75, .35);
|
||||
}
|
||||
|
||||
/* ===== Ajustes extra para móviles ===== */
|
||||
@media (max-width: 420px) {
|
||||
.ib-rewards {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.ib-card {
|
||||
padding: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== Libro: reduce presencia o desaparece en móvil ===== */
|
||||
@media (max-width: 1100px) {
|
||||
.ib-loyalty-banner .book.small {
|
||||
opacity: .55;
|
||||
left: 10px;
|
||||
bottom: 10px;
|
||||
width: 120px;
|
||||
height: 95px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 520px) {
|
||||
.ib-loyalty-banner .book.small {
|
||||
display: none;
|
||||
/* fuera en móviles pequeños */
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== OPCIONAL: hero más compacto en móvil ===== */
|
||||
@media (max-width: 520px) {
|
||||
.ib-loyalty-head {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.ib-loyalty-logo {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
.ib-loyalty-logo img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.ib-loyalty-left{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 18px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ib-loyalty-stat-card{
|
||||
|
||||
/* centra en el espacio libre */
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
|
||||
/* mismo look que el hero */
|
||||
background: var(--banner-panel-bg);
|
||||
border: 2px solid var(--banner-panel-border);
|
||||
border-radius: var(--radius-lg);
|
||||
|
||||
padding: 22px;
|
||||
max-width: 360px; /* evita que se haga enorme */
|
||||
}
|
||||
|
||||
.ib-loyalty-stat-card h6{
|
||||
letter-spacing: .4px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.ib-loyalty-stat-card h2{
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.ib-loyalty-stat-card i{
|
||||
opacity: .85;
|
||||
}
|
||||
|
||||
@media (max-width: 1100px){
|
||||
.ib-loyalty-stat-card{
|
||||
margin-top: 12px;
|
||||
margin-bottom: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
84
src/main/resources/static/assets/images/open-book.svg
Normal file
84
src/main/resources/static/assets/images/open-book.svg
Normal file
@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg fill="#ffffff" height="800px" width="800px" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 511 511" xml:space="preserve">
|
||||
<g>
|
||||
<path d="M487.5,128.106H479v-24.5c0-2.905-1.678-5.549-4.307-6.786C405.088,64.066,325.408,63.6,255.5,95.371
|
||||
C185.592,63.6,105.912,64.067,36.307,96.82C33.678,98.057,32,100.701,32,103.606v24.5h-8.5c-12.958,0-23.5,10.542-23.5,23.5v264
|
||||
c0,12.958,10.542,23.5,23.5,23.5h464c12.958,0,23.5-10.542,23.5-23.5v-264C511,138.648,500.458,128.106,487.5,128.106z
|
||||
M263,239.583c0-0.009,0-0.019,0-0.028V108.416c64.137-28.707,136.861-28.707,201,0v27.161c0,0.01-0.001,0.02-0.001,0.029
|
||||
s0.001,0.02,0.001,0.029v244.438c-32.237-13.461-66.371-20.193-100.5-20.193c-34.129,0-68.264,6.732-100.5,20.193V239.583z
|
||||
M215,96.391c11.187,3.204,22.217,7.198,33,12.025v117.177l-12.34-8.227c-2.52-1.68-5.801-1.68-8.32,0L215,225.593V96.391z
|
||||
M47,135.626c0-0.007,0.001-0.013,0.001-0.02S47,135.594,47,135.587v-27.171c48.563-21.736,102.046-26.999,153-15.82v32.856
|
||||
c-26.767-5.505-54.078-6.777-81.328-3.75c-4.117,0.457-7.083,4.165-6.626,8.282c0.458,4.116,4.162,7.085,8.282,6.626
|
||||
c26.708-2.967,53.479-1.562,79.671,4.165v48.686c-15.912-3.265-32.14-5.067-48.377-5.323c-4.145-0.078-7.552,3.239-7.618,7.38
|
||||
c-0.065,4.142,3.239,7.552,7.38,7.618c16.331,0.258,32.654,2.164,48.614,5.647v16.66c-43.389-8.909-88.39-6.644-130.748,6.665
|
||||
c-3.952,1.241-6.148,5.451-4.907,9.403c1.007,3.204,3.964,5.254,7.153,5.254c0.745,0,1.502-0.112,2.25-0.347
|
||||
c40.908-12.852,84.428-14.773,126.252-5.638v2.825c0,2.766,1.522,5.308,3.961,6.612c2.438,1.306,5.398,1.162,7.699-0.372
|
||||
l19.84-13.227l16.5,11v136.454c-32.237-13.461-66.371-20.193-100.5-20.193c-34.129,0-68.264,6.732-100.5,20.193V135.626z
|
||||
M224,424.106H23.5c-4.687,0-8.5-3.813-8.5-8.5v-264c0-4.687,3.813-8.5,8.5-8.5H32v248.5v8c0,4.142,3.358,7.5,7.5,7.5H224V424.106z
|
||||
M57.29,392.106c58.099-22.934,122.32-22.935,180.42,0H57.29z M272,424.106h-33v-17h33V424.106z M453.71,392.106H273.29
|
||||
C331.389,369.172,395.61,369.172,453.71,392.106z M496,415.606c0,4.687-3.813,8.5-8.5,8.5H287v-17h184.5c4.142,0,7.5-3.358,7.5-7.5
|
||||
v-8v-248.5h8.5c4.687,0,8.5,3.813,8.5,8.5V415.606z"/>
|
||||
<path d="M309.96,317.749c-8.302,1.74-16.615,3.911-24.708,6.454c-3.952,1.242-6.148,5.452-4.907,9.403
|
||||
c1.007,3.204,3.964,5.254,7.153,5.254c0.745,0,1.502-0.112,2.25-0.347c7.628-2.396,15.464-4.443,23.288-6.083
|
||||
c4.054-0.85,6.652-4.825,5.802-8.879C317.989,319.497,314.011,316.9,309.96,317.749z"/>
|
||||
<path d="M439.502,338.859c3.189,0,6.147-2.051,7.153-5.254c1.241-3.952-0.956-8.162-4.907-9.403
|
||||
c-32.073-10.076-65.329-13.842-98.844-11.188c-4.129,0.326-7.211,3.938-6.885,8.068s3.935,7.213,8.068,6.885
|
||||
c31.59-2.499,62.935,1.048,93.165,10.546C438,338.748,438.757,338.859,439.502,338.859z"/>
|
||||
<path d="M287.498,306.767c0.745,0,1.502-0.112,2.25-0.347c48.249-15.159,99.256-15.159,147.504,0
|
||||
c3.952,1.24,8.162-0.956,9.403-4.907c1.241-3.952-0.956-8.162-4.907-9.403c-51.191-16.083-105.306-16.083-156.496,0
|
||||
c-3.952,1.241-6.149,5.451-4.907,9.403C281.352,304.716,284.309,306.767,287.498,306.767z"/>
|
||||
<path d="M287.498,274.859c0.745,0,1.502-0.112,2.25-0.347c27.681-8.697,56.409-12.412,85.399-11.037
|
||||
c4.147,0.192,7.651-2.999,7.847-7.137c0.196-4.138-2.999-7.65-7.137-7.847c-30.753-1.456-61.236,2.483-90.605,11.71
|
||||
c-3.952,1.242-6.149,5.452-4.907,9.403C281.352,272.81,284.309,274.859,287.498,274.859z"/>
|
||||
<path d="M441.748,260.202c-10.76-3.38-21.846-6.086-32.952-8.043c-4.08-0.719-7.968,2.006-8.688,6.085
|
||||
c-0.719,4.079,2.005,7.969,6.085,8.688c10.467,1.844,20.917,4.395,31.058,7.581c0.749,0.235,1.505,0.347,2.25,0.347
|
||||
c3.189,0,6.147-2.051,7.153-5.254C447.896,265.653,445.7,261.443,441.748,260.202z"/>
|
||||
<path d="M287.498,242.767c0.745,0,1.502-0.112,2.25-0.347c48.249-15.159,99.256-15.159,147.504,0
|
||||
c3.952,1.24,8.162-0.956,9.403-4.907c1.241-3.952-0.956-8.162-4.907-9.403c-51.191-16.083-105.306-16.083-156.496,0
|
||||
c-3.952,1.241-6.149,5.451-4.907,9.403C281.352,240.716,284.309,242.767,287.498,242.767z"/>
|
||||
<path d="M334.678,185.702c-16.732,1.858-33.362,5.36-49.426,10.407c-3.952,1.241-6.148,5.451-4.907,9.403
|
||||
c1.007,3.204,3.964,5.254,7.153,5.254c0.745,0,1.502-0.112,2.25-0.347c15.141-4.757,30.815-8.057,46.585-9.809
|
||||
c4.117-0.457,7.083-4.165,6.626-8.282S338.79,185.244,334.678,185.702z"/>
|
||||
<path d="M367.386,199.137c23.725,0.375,47.231,4.17,69.866,11.283c0.748,0.234,1.505,0.347,2.25,0.347
|
||||
c3.189,0,6.146-2.051,7.153-5.254c1.241-3.952-0.956-8.162-4.907-9.403c-24.015-7.545-48.955-11.572-74.125-11.97
|
||||
c-4.125-0.078-7.552,3.239-7.618,7.38S363.244,199.072,367.386,199.137z"/>
|
||||
<path d="M390.671,168.704c4.116,0.46,7.825-2.509,8.282-6.626c0.458-4.117-2.509-7.825-6.626-8.282
|
||||
c-36.252-4.027-72.278-0.526-107.075,10.406c-3.952,1.242-6.148,5.452-4.907,9.403c1.007,3.204,3.964,5.254,7.153,5.254
|
||||
c0.745,0,1.502-0.112,2.25-0.347C322.545,168.208,356.5,164.909,390.671,168.704z"/>
|
||||
<path d="M441.748,164.202c-5.418-1.702-10.96-3.246-16.472-4.588c-4.03-0.98-8.082,1.488-9.062,5.512
|
||||
c-0.98,4.024,1.488,8.082,5.512,9.062c5.196,1.265,10.419,2.72,15.526,4.324c0.748,0.235,1.505,0.347,2.25,0.347
|
||||
c3.189,0,6.147-2.051,7.153-5.254C447.896,169.653,445.7,165.443,441.748,164.202z"/>
|
||||
<path d="M287.498,146.767c0.745,0,1.502-0.112,2.25-0.347c5.103-1.604,10.325-3.058,15.521-4.324
|
||||
c4.024-0.98,6.492-5.037,5.512-9.062s-5.038-6.492-9.062-5.512c-5.513,1.342-11.053,2.886-16.468,4.587
|
||||
c-3.951,1.242-6.148,5.452-4.907,9.403C281.352,144.716,284.309,146.767,287.498,146.767z"/>
|
||||
<path d="M336.329,136.611c34.172-3.796,68.126-0.496,100.923,9.809c0.748,0.234,1.505,0.347,2.25,0.347
|
||||
c3.189,0,6.146-2.051,7.153-5.254c1.241-3.952-0.956-8.162-4.907-9.403c-34.797-10.933-70.824-14.435-107.076-10.406
|
||||
c-4.117,0.457-7.083,4.165-6.626,8.282C328.504,134.102,332.21,137.07,336.329,136.611z"/>
|
||||
<path d="M93.96,317.749c-8.302,1.74-16.615,3.911-24.708,6.454c-3.952,1.242-6.148,5.452-4.907,9.403
|
||||
c1.007,3.204,3.964,5.254,7.153,5.254c0.745,0,1.502-0.112,2.25-0.347c7.628-2.396,15.464-4.443,23.288-6.083
|
||||
c4.054-0.85,6.652-4.825,5.802-8.879S98.011,316.9,93.96,317.749z"/>
|
||||
<path d="M223.502,338.859c3.189,0,6.147-2.051,7.153-5.254c1.241-3.952-0.956-8.162-4.907-9.403
|
||||
c-32.073-10.076-65.331-13.842-98.844-11.188c-4.129,0.326-7.211,3.938-6.885,8.068s3.934,7.213,8.068,6.885
|
||||
c31.591-2.499,62.935,1.048,93.165,10.546C222,338.748,222.757,338.859,223.502,338.859z"/>
|
||||
<path d="M71.498,306.767c0.745,0,1.502-0.112,2.25-0.347c48.249-15.159,99.256-15.159,147.504,0
|
||||
c3.952,1.24,8.162-0.956,9.403-4.907c1.241-3.952-0.956-8.162-4.907-9.403c-51.191-16.083-105.307-16.083-156.496,0
|
||||
c-3.952,1.241-6.149,5.451-4.907,9.403C65.352,304.716,68.309,306.767,71.498,306.767z"/>
|
||||
<path d="M71.498,274.859c0.745,0,1.502-0.112,2.25-0.347c27.681-8.697,56.411-12.412,85.399-11.037
|
||||
c4.158,0.192,7.65-2.999,7.847-7.137c0.196-4.138-2.999-7.65-7.137-7.847c-30.756-1.456-61.236,2.483-90.605,11.71
|
||||
c-3.952,1.242-6.149,5.452-4.907,9.403C65.352,272.81,68.309,274.859,71.498,274.859z"/>
|
||||
<path d="M190.194,266.932c10.467,1.844,20.917,4.395,31.058,7.581c0.749,0.235,1.505,0.347,2.25,0.347
|
||||
c3.189,0,6.147-2.051,7.153-5.254c1.241-3.952-0.956-8.162-4.907-9.403c-10.76-3.38-21.846-6.086-32.952-8.043
|
||||
c-4.079-0.719-7.969,2.006-8.688,6.085C183.39,262.323,186.114,266.213,190.194,266.932z"/>
|
||||
<path d="M118.678,185.702c-16.732,1.858-33.362,5.36-49.426,10.407c-3.952,1.241-6.148,5.451-4.907,9.403
|
||||
c1.007,3.204,3.964,5.254,7.153,5.254c0.745,0,1.502-0.112,2.25-0.347c15.141-4.757,30.815-8.057,46.585-9.809
|
||||
c4.117-0.457,7.083-4.165,6.626-8.282C126.503,188.212,122.788,185.244,118.678,185.702z"/>
|
||||
<path d="M64.345,173.605c1.007,3.204,3.964,5.254,7.153,5.254c0.745,0,1.502-0.112,2.25-0.347
|
||||
c32.797-10.305,66.752-13.604,100.923-9.809c4.116,0.46,7.825-2.509,8.282-6.626c0.458-4.117-2.509-7.825-6.626-8.282
|
||||
c-36.253-4.027-72.278-0.526-107.075,10.406C65.3,165.444,63.104,169.654,64.345,173.605z"/>
|
||||
<path d="M71.498,146.767c0.745,0,1.502-0.112,2.25-0.347c5.103-1.604,10.325-3.058,15.521-4.324
|
||||
c4.024-0.98,6.492-5.037,5.512-9.062s-5.038-6.492-9.062-5.512c-5.513,1.342-11.053,2.886-16.468,4.587
|
||||
c-3.951,1.242-6.148,5.452-4.907,9.403C65.352,144.716,68.309,146.767,71.498,146.767z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.0 KiB |
@ -0,0 +1,34 @@
|
||||
import {formateaMoneda} from "./utils.js";
|
||||
|
||||
$(() => {
|
||||
// Contador animado
|
||||
function counter() {
|
||||
var counter = document.querySelectorAll(".counter-value");
|
||||
var speed = 250; // The lower the slower
|
||||
counter &&
|
||||
Array.from(counter).forEach(function (counter_value) {
|
||||
function updateCount() {
|
||||
var target = +counter_value.getAttribute("data-target");
|
||||
var count = +counter_value.innerText;
|
||||
var inc = target / speed;
|
||||
if (inc < 1) {
|
||||
inc = 1;
|
||||
}
|
||||
// Check if target is reached
|
||||
if (count < target) {
|
||||
// Add inc to count and output in counter_value
|
||||
counter_value.innerText = (count + inc).toFixed(0);
|
||||
// Call function every ms
|
||||
setTimeout(updateCount, 1);
|
||||
} else {
|
||||
counter_value.innerText = formateaMoneda(target);
|
||||
}
|
||||
formateaMoneda(counter_value.innerText);
|
||||
}
|
||||
updateCount();
|
||||
});
|
||||
|
||||
}
|
||||
counter();
|
||||
|
||||
})
|
||||
@ -0,0 +1,216 @@
|
||||
$(() => {
|
||||
const csrfToken = document.querySelector('meta[name="_csrf"]')?.getAttribute('content');
|
||||
const csrfHeader = document.querySelector('meta[name="_csrf_header"]')?.getAttribute('content');
|
||||
if (window.$ && csrfToken && csrfHeader) {
|
||||
$.ajaxSetup({
|
||||
beforeSend: function (xhr) {
|
||||
xhr.setRequestHeader(csrfHeader, csrfToken);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let $addBtn = $('#save-btn');
|
||||
let $cancelBtn = $('#cancel-btn');
|
||||
let $selectCliente = $('#clienteSelect');
|
||||
let $serieInput = $('#serieInput');
|
||||
let $direccionFacturacion = $('#direccionFacturacion');
|
||||
let $facturaRectificada = $('#facturaRectificada');
|
||||
let $divFacturaRectificada = $('#div-factura-rectificada');
|
||||
|
||||
// -----------------------------
|
||||
// Initialize select2 for cliente selection
|
||||
// -----------------------------
|
||||
$selectCliente.select2({
|
||||
placeholder: languageBundle['facturas.form.cliente.placeholder'],
|
||||
width: '100%',
|
||||
ajax: {
|
||||
url: '/users/api/get-users',
|
||||
dataType: 'json',
|
||||
delay: 250,
|
||||
data: function (params) {
|
||||
return {
|
||||
showUsername: true,
|
||||
q: params.term,
|
||||
page: params.page || 1
|
||||
};
|
||||
}
|
||||
},
|
||||
minimumInputLength: 0
|
||||
});
|
||||
|
||||
$selectCliente.on('select2:select', function (e) {
|
||||
const data = e.params.data;
|
||||
$serieInput.val(null).trigger('change');
|
||||
$direccionFacturacion.val(null).trigger('change');
|
||||
$facturaRectificada.val(null).trigger('change');
|
||||
if (data && data.id) {
|
||||
$serieInput.prop('disabled', false);
|
||||
$direccionFacturacion.prop('disabled', false);
|
||||
}
|
||||
else {
|
||||
$serieInput.prop('disabled', true);
|
||||
$direccionFacturacion.prop('disabled', true);
|
||||
}
|
||||
});
|
||||
|
||||
$serieInput.select2({
|
||||
placeholder: languageBundle['facturas.form.serie.placeholder'],
|
||||
width: '100%',
|
||||
ajax: {
|
||||
url: '/configuracion/series-facturacion/api/get-series',
|
||||
dataType: 'json',
|
||||
delay: 250,
|
||||
data: function (params) {
|
||||
return {
|
||||
q: params.term,
|
||||
page: params.page || 1
|
||||
};
|
||||
}
|
||||
},
|
||||
minimumInputLength: 0
|
||||
});
|
||||
|
||||
$serieInput.on('select2:select', function (e) {
|
||||
const data = e.params.data;
|
||||
const defaultRectSerieId = $serieInput.data('default-serie-rect');
|
||||
if (data && data.id) {
|
||||
if (data.id === defaultRectSerieId) {
|
||||
$divFacturaRectificada.removeClass('d-none');
|
||||
$facturaRectificada.val(null).trigger('change');
|
||||
}
|
||||
else {
|
||||
$divFacturaRectificada.addClass('d-none');
|
||||
$facturaRectificada.val(null).trigger('change');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$direccionFacturacion.select2({
|
||||
placeholder: languageBundle['facturas.form.direccion-facturacion.placeholder'],
|
||||
width: '100%',
|
||||
ajax: {
|
||||
url: '/facturas/api/get-direcciones',
|
||||
dataType: 'json',
|
||||
delay: 250,
|
||||
data: function (params) {
|
||||
const clienteId = $selectCliente.val();
|
||||
return {
|
||||
user_id: clienteId,
|
||||
q: params.term,
|
||||
page: params.page || 1
|
||||
};
|
||||
},
|
||||
processResults: (data) => {
|
||||
const items = Array.isArray(data) ? data : (data.results || []);
|
||||
return {
|
||||
results: items.map(item => ({
|
||||
id: item.id,
|
||||
text: item.text, // ← Select2 necesita 'id' y 'text'
|
||||
alias: item.alias || 'Sin alias',
|
||||
att: item.att || '',
|
||||
direccion: item.direccion || '',
|
||||
cp: item.cp || '',
|
||||
ciudad: item.ciudad || '',
|
||||
html: `
|
||||
<div>
|
||||
<strong>${item.alias || 'Sin alias'}</strong><br>
|
||||
${item.att ? `<small>${item.att}</small><br>` : ''}
|
||||
<small>${item.direccion || ''}${item.cp ? ', ' + item.cp : ''}${item.ciudad ? ', ' + item.ciudad : ''}</small>
|
||||
</div>
|
||||
`
|
||||
})),
|
||||
pagination: { more: false } // opcional, evita que espere más páginas
|
||||
};
|
||||
}
|
||||
},
|
||||
minimumInputLength: 0,
|
||||
templateResult: data => {
|
||||
if (data.loading) return data.text;
|
||||
return $(data.html || data.text);
|
||||
},
|
||||
// Selección más compacta (solo alias + ciudad)
|
||||
templateSelection: data => {
|
||||
if (!data.id) return data.text;
|
||||
const alias = data.alias || data.text;
|
||||
const ciudad = data.ciudad ? ` — ${data.ciudad}` : '';
|
||||
return $(`<span>${alias}${ciudad}</span>`);
|
||||
},
|
||||
escapeMarkup: m => m
|
||||
});
|
||||
|
||||
$facturaRectificada.select2({
|
||||
placeholder: languageBundle['facturas.form.factura-rectificada.placeholder'],
|
||||
width: '100%',
|
||||
ajax: {
|
||||
url: '/facturas/api/get-facturas-rectificables',
|
||||
dataType: 'json',
|
||||
delay: 250,
|
||||
data: function (params) {
|
||||
const clienteId = $selectCliente.val();
|
||||
return {
|
||||
user_id: clienteId,
|
||||
q: params.term,
|
||||
page: params.page || 1
|
||||
};
|
||||
}
|
||||
},
|
||||
minimumInputLength: 0
|
||||
});
|
||||
|
||||
// -----------------------------
|
||||
// Cancel button click
|
||||
// -----------------------------
|
||||
$cancelBtn.on('click', () => {
|
||||
window.location.href = '/facturas';
|
||||
});
|
||||
|
||||
// -----------------------------
|
||||
// Save button click
|
||||
// -----------------------------
|
||||
$addBtn.on('click', () => {
|
||||
const clienteId = $selectCliente.val();
|
||||
const serieId = $serieInput.val();
|
||||
const direccionId = $direccionFacturacion.val();
|
||||
const facturaRectificadaId = $facturaRectificada.val();
|
||||
|
||||
if (!clienteId && !serieId && !direccionId) {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: languageBundle['facturas.add.form.validation.title'],
|
||||
text: languageBundle['facturas.add.form.validation']
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: '/facturas/add',
|
||||
method: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({
|
||||
user: clienteId,
|
||||
serie: serieId,
|
||||
direccion: direccionId,
|
||||
factura_rectificada: facturaRectificadaId
|
||||
}),
|
||||
success: function (response) {
|
||||
if (response.success) {
|
||||
window.location.href = '/facturas/' + response.facturaId;
|
||||
} else {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Error',
|
||||
text: response.message
|
||||
});
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Error',
|
||||
text: languageBundle['facturas.error.create']
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -62,7 +62,9 @@ $(() => {
|
||||
// -----------------------------
|
||||
// Add
|
||||
// -----------------------------
|
||||
$addBtn.on();
|
||||
$addBtn.on('click', () => {
|
||||
window.location.href = '/facturas/add';
|
||||
});
|
||||
|
||||
// -----------------------------
|
||||
// Edit click
|
||||
|
||||
@ -83,4 +83,20 @@ $(() => {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if ($(".btn-download-factura").length) {
|
||||
$(document).on('click', '.btn-download-factura', function () {
|
||||
const facturaId = $(this).data('factura-id');
|
||||
|
||||
const url = `/api/pdf/factura/${facturaId}?mode=download`;
|
||||
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.target = '_self'; // descarga en la misma pestaña
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
@ -318,6 +318,50 @@ export default class PresupuestoWizard {
|
||||
document.body.removeChild(a);
|
||||
});
|
||||
|
||||
$(document)
|
||||
.off('click.login-required', '.btn-login-required')
|
||||
.on('click.login-required', '.btn-login-required', async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const rawId = this.opts.presupuestoId || window.PRESUPUESTO_ID || $('#presupuesto_id').val();
|
||||
const presupuestoId = rawId ? parseInt(rawId, 10) : null;
|
||||
|
||||
if (!presupuestoId || Number.isNaN(presupuestoId)) {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'No se encontró el presupuesto',
|
||||
text: 'Vuelve a generar el resumen e inténtalo de nuevo.',
|
||||
buttonsStyling: false,
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-secondary me-2',
|
||||
cancelButton: 'btn btn-light'
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await $.ajax({
|
||||
url: '/presupuesto/public/prepare-claim',
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({ presupuestoId })
|
||||
});
|
||||
window.location.assign('/presupuesto/claim');
|
||||
} catch (err) {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'No se pudo continuar',
|
||||
text: 'Inténtalo de nuevo en unos segundos.',
|
||||
buttonsStyling: false,
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-secondary me-2',
|
||||
cancelButton: 'btn btn-light'
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -1853,6 +1897,15 @@ export default class PresupuestoWizard {
|
||||
...result,
|
||||
};
|
||||
|
||||
if (!this.formData.servicios.servicios.some(s => s.id === "marcapaginas") && result.precio > 0) {
|
||||
this.formData.servicios.servicios.push({
|
||||
id: "marcapaginas",
|
||||
label: $(`label[for="marcapaginas"] .service-title`).text().trim(),
|
||||
units: 1,
|
||||
price: result.precio,
|
||||
});
|
||||
}
|
||||
|
||||
this.#cacheFormData();
|
||||
});
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { duplicar, reimprimir } from './presupuesto-utils.js';
|
||||
(() => {
|
||||
// si jQuery está cargado, añade CSRF a AJAX
|
||||
const csrfToken = document.querySelector('meta[name="_csrf"]')?.getAttribute('content');
|
||||
@ -124,6 +125,27 @@
|
||||
});
|
||||
});
|
||||
|
||||
$('#presupuestos-clientes-user-datatable').on('click', '.btn-duplicate-privado', function (e) {
|
||||
|
||||
e.preventDefault();
|
||||
const id = $(this).data('id');
|
||||
let data = table.row($(this).parents('tr')).data();
|
||||
const tituloOriginal = data.titulo;
|
||||
|
||||
duplicar(id, tituloOriginal);
|
||||
});
|
||||
|
||||
$('#presupuestos-clientes-user-datatable').on('click', '.btn-reprint-privado', function (e) {
|
||||
|
||||
e.preventDefault();
|
||||
const id = $(this).data('id');
|
||||
let data = table.row($(this).parents('tr')).data();
|
||||
const tituloOriginal = data.titulo;
|
||||
|
||||
reimprimir(id, tituloOriginal);
|
||||
});
|
||||
|
||||
|
||||
$('#presupuestos-clientes-user-datatable').on('keyup', '.presupuesto-filter', function (e) {
|
||||
const colName = $(this).data('col');
|
||||
const colIndex = table.column(colName + ':name').index();
|
||||
|
||||
@ -147,6 +147,55 @@ $(() => {
|
||||
});
|
||||
});
|
||||
|
||||
// Botón "Entrar como"
|
||||
$(document).on('click', '.btn-impersonate-user', function (e) {
|
||||
e.preventDefault();
|
||||
const username = $(this).data('username');
|
||||
|
||||
const title = window.languageBundle.get(['usuarios.impersonate.title']) || 'Entrar como usuario';
|
||||
const textTpl = window.languageBundle.get(['usuarios.impersonate.text'])
|
||||
|| 'Vas a iniciar sesión como <b>{0}</b>.';
|
||||
const confirmText = window.languageBundle.get(['usuarios.impersonate.button']) || 'Entrar';
|
||||
|
||||
Swal.fire({
|
||||
title,
|
||||
html: textTpl.replace('{0}', username),
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
buttonsStyling: false,
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-info w-xs mt-2',
|
||||
cancelButton: 'btn btn-light w-xs mt-2'
|
||||
},
|
||||
confirmButtonText: confirmText,
|
||||
cancelButtonText: window.languageBundle.get(['app.cancelar']) || 'Cancelar',
|
||||
}).then((result) => {
|
||||
if (!result.isConfirmed) return;
|
||||
|
||||
$.ajax({
|
||||
url: '/impersonate',
|
||||
type: 'POST',
|
||||
data: { username },
|
||||
success: function () {
|
||||
window.location.href = '/';
|
||||
},
|
||||
error: function (xhr) {
|
||||
const msg = (xhr.responseJSON && xhr.responseJSON.message)
|
||||
|| 'No se pudo iniciar sesión como ese usuario.';
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'No se pudo suplantar',
|
||||
text: msg,
|
||||
buttonsStyling: false,
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-secondary me-2',
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Submit del form en el modal
|
||||
$(document).on('submit', '#userForm', function (e) {
|
||||
|
||||
@ -0,0 +1,120 @@
|
||||
<!doctype html>
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{imprimelibros/layout}">
|
||||
|
||||
<head>
|
||||
<th:block layout:fragment="pagetitle" />
|
||||
<th:block th:replace="~{imprimelibros/partials/head-css :: head-css}" />
|
||||
<th:block layout:fragment="pagecss">
|
||||
<link th:href="@{/assets/css/presupuestador.css}" rel="stylesheet"
|
||||
th:unless="${#authorization.expression('isAuthenticated()')}" />
|
||||
<link th:href="@{/assets/libs/datatables/dataTables.bootstrap5.min.css}" rel="stylesheet" />
|
||||
<link sec:authorize="isAuthenticated() and hasAnyRole('SUPERADMIN','ADMIN')"
|
||||
th:href="@{/assets/libs/quill/quill.snow.css}" rel="stylesheet" type="text/css" />
|
||||
</th:block>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div th:replace="~{imprimelibros/partials/topbar :: topbar}" />
|
||||
<div th:replace="~{imprimelibros/partials/sidebar :: sidebar}" />
|
||||
|
||||
<th:block layout:fragment="content">
|
||||
<div th:if="${#authorization.expression('isAuthenticated()')}">
|
||||
|
||||
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/"><i class="ri-home-5-fill"></i></a></li>
|
||||
<li class="breadcrumb-item"><a href="/facturas" th:text="#{facturas.breadcrumb}"></a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page" th:text="#{facturas.breadcrumb.nueva}">
|
||||
Nueva factura</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="container-fluid position-relative">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-md-6 mb-3">
|
||||
<label for="clienteSelect" class="form-label" th:text="#{facturas.form.cliente}">Cliente</label>
|
||||
<select id="clienteSelect" class="form-select select2"
|
||||
th:placeholder="#{facturas.form.cliente.placeholder}">
|
||||
<option th:each="cliente : ${clientes}" th:value="${cliente.id}"
|
||||
th:text="${cliente.nombre} + ' (' + cliente.email + ')'"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-6 mb-3">
|
||||
<label for="serieInput" class="form-label" th:text="#{facturas.form.serie}">Serie de
|
||||
facturación</label>
|
||||
<select id="serieInput" class="form-select select2" disabled
|
||||
th:data-default-serie-rect="${defaultSerieRectificativa}">
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- salto de fila SOLO en md+ -->
|
||||
<div class="w-100 d-none d-md-block"></div>
|
||||
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<label for="direccionFacturacion" class="form-label"
|
||||
th:text="#{facturas.form.direccion-facturacion}">
|
||||
Factura rectificada
|
||||
</label>
|
||||
<select id="direccionFacturacion" class="form-select select2" disabled></select>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-6 mb-3 d-none" id="div-factura-rectificada">
|
||||
<label for="facturaRectificada" class="form-label"
|
||||
th:text="#{facturas.form.factura-rectificada}">
|
||||
Factura rectificada
|
||||
</label>
|
||||
<select id="facturaRectificada" class="form-select select2"></select>
|
||||
</div>
|
||||
</div> <!-- end row -->
|
||||
|
||||
<div class="row mt-3 justify-content-md-end g-2">
|
||||
<div class="col-12 col-md-auto">
|
||||
<button type="button" th:text="#{app.guardar}" id="save-btn" class="btn btn-secondary w-100">
|
||||
Guardar
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-auto">
|
||||
<button type="button" th:text="#{app.cancelar}" id="cancel-btn" class="btn btn-light w-100">
|
||||
Cancelar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</th:block>
|
||||
|
||||
<th:block layout:fragment="modal" />
|
||||
<th:block th:replace="~{theme/partials/vendor-scripts :: scripts}" />
|
||||
<th:block layout:fragment="pagejs">
|
||||
<script th:inline="javascript">
|
||||
window.languageBundle = /*[[${languageBundle}]]*/ {};
|
||||
</script>
|
||||
<script th:src="@{/assets/libs/datatables/datatables.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/datatables/dataTables.bootstrap5.min.js}"></script>
|
||||
|
||||
<!-- JS de Buttons y dependencias -->
|
||||
<script th:src="@{/assets/libs/datatables/dataTables.buttons.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/jszip/jszip.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/pdfmake/pdfmake.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/pdfmake/vfs_fonts.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/datatables/buttons.html5.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/datatables/buttons.print.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/datatables/buttons.colVis.min.js}"></script>
|
||||
|
||||
<script sec:authorize="isAuthenticated() and hasAnyRole('SUPERADMIN','ADMIN')"
|
||||
th:src="@{/assets/libs/quill/quill.min.js}"></script>
|
||||
|
||||
<script type="module" th:src="@{/assets/js/pages/imprimelibros/facturas/add.js}"></script>
|
||||
|
||||
</th:block>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@ -16,10 +16,14 @@
|
||||
<div class="row g-3">
|
||||
|
||||
<!-- Número (solo lectura siempre, normalmente) -->
|
||||
<div class="col-md-3">
|
||||
<div th:if="${factura.numeroFactura != null}" class="col-md-3">
|
||||
<label class="form-label" th:text="#{facturas.form.numero-factura}">Número de factura</label>
|
||||
<input id="facturaNumero" type="text" class="form-control" th:value="${factura.numeroFactura}" readonly>
|
||||
</div>
|
||||
<div th:if="${factura.numeroFactura == null}" class="col-md-3">
|
||||
<label class="form-label" th:text="#{facturas.form.id}">ID de la factura</label>
|
||||
<input id="facturaId" type="text" class="form-control" th:value="${factura.id}" readonly>
|
||||
</div>
|
||||
|
||||
<!-- Serie -->
|
||||
<div class="col-md-3">
|
||||
@ -43,6 +47,15 @@
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Factura rectificada -->
|
||||
<div th:if="${factura.facturaRectificada != null}" class="w-100 d-md-block"></div>
|
||||
<div th:if="${factura.facturaRectificada != null}" class="col-md-3">
|
||||
<label class="form-label" th:text="#{facturas.form.factura-rectificada}">Factura rectificada</label>
|
||||
<input readonly id="facturaRectificadaId" class="form-control"
|
||||
th:value="${factura.facturaRectificada.numeroFactura}" />
|
||||
</div>
|
||||
<div th:if="${factura.facturaRectificada != null}" class="w-100 d-md-block"></div>
|
||||
|
||||
<div class="col-md-3">
|
||||
<label class="form-label" th:text="#{facturas.form.fecha-emision}">Fecha</label>
|
||||
|
||||
|
||||
@ -0,0 +1,105 @@
|
||||
<div id="fidelity-banner" th:fragment="home-container-user">
|
||||
|
||||
<div class="ib-loyalty-banner">
|
||||
|
||||
<!-- Decoraciones -->
|
||||
<div class="decor"></div>
|
||||
<div class="book small"></div>
|
||||
|
||||
<div class="ib-loyalty-inner">
|
||||
|
||||
<!-- ===================== -->
|
||||
<!-- COLUMNA IZQUIERDA -->
|
||||
<!-- ===================== -->
|
||||
<div class="ib-loyalty-left">
|
||||
|
||||
<!-- PANEL SUPERIOR: TÍTULO -->
|
||||
<div class="ib-loyalty-hero">
|
||||
<div class="ib-loyalty-head">
|
||||
<div class="ib-loyalty-logo">
|
||||
<img src="/assets/images/logo-sm.png" alt="Logo" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 class="ib-loyalty-title">Programa de Fidelidad</h3>
|
||||
<p class="ib-loyalty-sub">
|
||||
Aumenta tus compras en los últimos 12 meses y obtén descuentos automáticos.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- PANEL INFERIOR: ESTADÍSTICA (RECUADRO INDEPENDIENTE) -->
|
||||
<div class="ib-loyalty-stat-card">
|
||||
|
||||
<h6 class="text-uppercase fs-13 mb-3">
|
||||
<span th:text="#{pedido.gasto-anual}">Gasto últimos 12 meses</span>
|
||||
<i class="ri-arrow-up-circle-line text-success fs-18 float-end align-middle"></i>
|
||||
</h6>
|
||||
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="flex-shrink-0">
|
||||
<i class="ri-money-euro-circle-line display-6 "></i>
|
||||
</div>
|
||||
<div class="flex-grow-1 ms-3">
|
||||
<h2 class="mb-0">
|
||||
<h2 class="mb-0"><span class="counter-value" th:attr="data-target=${totalGastado}">0</span></h2>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ===================== -->
|
||||
<!-- COLUMNA DERECHA -->
|
||||
<!-- ===================== -->
|
||||
<div class="ib-rewards">
|
||||
|
||||
<h6>Recompensas</h6>
|
||||
|
||||
<div class="ib-rewards-grid">
|
||||
|
||||
<div class="ib-card">
|
||||
<div class="range">Menos de 1.200€</div>
|
||||
<div class="percent">0%</div>
|
||||
<span class="chip">Descuento</span>
|
||||
</div>
|
||||
|
||||
<div class="ib-card">
|
||||
<div class="range">1.200€ – 1.999€</div>
|
||||
<div class="percent">1%</div>
|
||||
<span class="chip">Descuento</span>
|
||||
</div>
|
||||
|
||||
<div class="ib-card">
|
||||
<div class="range">2.000€ – 2.999€</div>
|
||||
<div class="percent">2%</div>
|
||||
<span class="chip">Descuento</span>
|
||||
</div>
|
||||
|
||||
<div class="ib-card">
|
||||
<div class="range">3.000€ – 3.999€</div>
|
||||
<div class="percent">3%</div>
|
||||
<span class="chip">Descuento</span>
|
||||
</div>
|
||||
|
||||
<div class="ib-card">
|
||||
<div class="range">4.000€ – 4.999€</div>
|
||||
<div class="percent">4%</div>
|
||||
<span class="chip">Descuento</span>
|
||||
</div>
|
||||
|
||||
<div class="ib-card">
|
||||
<div class="range">Más de 5.000€</div>
|
||||
<div class="percent">5%</div>
|
||||
<span class="chip">Descuento</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -8,6 +8,8 @@
|
||||
<th:block layout:fragment="pagecss">
|
||||
<link th:href="@{/assets/css/presupuestador.css}" rel="stylesheet"
|
||||
th:unless="${#authorization.expression('isAuthenticated()')}" />
|
||||
<link th:href="@{/assets/css/home.css}" rel="stylesheet"
|
||||
th:if="${#authorization.expression('isAuthenticated()')}" />
|
||||
</th:block>
|
||||
|
||||
</head>
|
||||
@ -22,7 +24,7 @@
|
||||
<th:block layout:fragment="content">
|
||||
<div th:if="${#authorization.expression('isAuthenticated()')}">
|
||||
<div class="container-fluid">
|
||||
|
||||
<div th:insert="~{imprimelibros/home/home-container-user :: home-container-user}"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div th:unless="${#authorization.expression('isAuthenticated()')}">
|
||||
@ -41,6 +43,9 @@
|
||||
<script type="module"
|
||||
th:src="@{/assets/js/pages/imprimelibros/presupuestador/presupuesto-marcapaginas.js}"></script>
|
||||
</div>
|
||||
<div th:if="${#authorization.expression('isAuthenticated()')}">
|
||||
<script type="module" th:src="@{/assets/js/pages/imprimelibros/counter-widget.js}"></script>
|
||||
</div>
|
||||
<script th:inline="javascript">
|
||||
window.languageBundle = /*[[${languageBundle}]]*/ {};
|
||||
</script>
|
||||
|
||||
@ -100,9 +100,14 @@
|
||||
<a class="dropdown-item" href="/pages-profile"><i
|
||||
class="mdi mdi-account-circle text-muted fs-16 align-middle me-1"></i> <span
|
||||
class="align-middle" th:text="#{app.perfil}">Perfil</span></a>
|
||||
<a class="dropdown-item" href="/apps-chat"><i
|
||||
class="mdi mdi-message-text-outline text-muted fs-16 align-middle me-1"></i>
|
||||
<span class="align-middle" th:text="#{app.mensajes}">Mensajes</span></a>
|
||||
<div sec:authorize="hasRole('PREVIOUS_ADMINISTRATOR')">
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="#"
|
||||
onclick="document.getElementById('exitImpersonationForm').submit(); return false;">
|
||||
<i class="mdi mdi-account-switch text-muted fs-16 align-middle me-1"></i>
|
||||
<span class="align-middle" th:text="#{app.impersonate.exit}">Volver a mi usuario</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="#"
|
||||
onclick="document.getElementById('logoutForm').submit(); return false;">
|
||||
@ -127,7 +132,10 @@
|
||||
<form id="logoutForm" th:action="@{/logout}" method="post" class="d-none">
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
|
||||
</form>
|
||||
<form id="exitImpersonationForm" th:action="@{/impersonate/exit}" method="post" class="d-none">
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
|
||||
</form>
|
||||
</header>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -73,24 +73,24 @@
|
||||
Aceptar ferro
|
||||
</button>
|
||||
|
||||
<button th:if="${item.estado.priority >= 7 && item.estado.priority < 11 && item.buttons.ferro}"
|
||||
<button
|
||||
th:if="${item.estado.priority >= 7 and item.estado.priority <= 11 and item['buttons'] != null and item['buttons']['ferro'] == true}"
|
||||
type="button" class="btn btn-light w-100 btn-download-ferro"
|
||||
th:text="#{pedido.view.ferro-download}"
|
||||
th:attr="data-linea-id=${item.lineaId}">
|
||||
th:text="#{pedido.view.ferro-download}" th:attr="data-linea-id=${item.lineaId}">
|
||||
Descargar ferro
|
||||
</button>
|
||||
|
||||
<button th:if="${item.estado.priority >= 7 && item.estado.priority < 11 && item.buttons.cub}"
|
||||
<button
|
||||
th:if="${item.estado.priority >= 7 and item.estado.priority <= 11 and item['buttons'] != null and item['buttons']['cub'] == true}"
|
||||
type="button" class="btn btn-light w-100 btn-download-cub"
|
||||
th:text="#{pedido.view.cub-download}"
|
||||
th:attr="data-linea-id=${item.lineaId}">
|
||||
th:text="#{pedido.view.cub-download}" th:attr="data-linea-id=${item.lineaId}">
|
||||
Descargar cubierta
|
||||
</button>
|
||||
|
||||
<button th:if="${item.estado.priority >= 7 && item.estado.priority < 11 && item.buttons.tapa}"
|
||||
<button
|
||||
th:if="${item.estado.priority >= 7 and item.estado.priority <= 11 and item['buttons'] != null and item['buttons']['tapa'] == true}"
|
||||
type="button" class="btn btn-light w-100 btn-download-tapa"
|
||||
th:text="#{pedido.view.tapa-download}"
|
||||
th:attr="data-linea-id=${item.lineaId}">
|
||||
th:text="#{pedido.view.tapa-download}" th:attr="data-linea-id=${item.lineaId}">
|
||||
Descargar tapa
|
||||
</button>
|
||||
</div>
|
||||
@ -136,7 +136,7 @@
|
||||
<div class="d-flex flex-wrap my-n1">
|
||||
<!-- Actualizar estado-->
|
||||
<div class="update-estado-button"
|
||||
th:if="${item.estado.name != 'cancelado' && item.estado.name != 'maquetacion' && item.estado.name != 'terminado'}">
|
||||
th:if="${item.estado.name != 'cancelado' && item.estado.name != 'maquetacion' && item.estado.name != 'enviado'}">
|
||||
<a href="javascript:void(0);" class="d-block text-body p-1 px-2 update-status-item"
|
||||
th:attr="data-linea-id=${item.lineaId}">
|
||||
<i class="ri-refresh-line text-muted align-bottom me-1"><span
|
||||
|
||||
@ -43,6 +43,7 @@
|
||||
pais=${direccionFacturacion != null ? direccionFacturacion.paisNombre : ''}
|
||||
)}">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<th:block th:if="${isAdmin and showCancel}">
|
||||
<div sec:authorize="isAuthenticated() and hasAnyRole('SUPERADMIN','ADMIN')"
|
||||
@ -60,11 +61,23 @@
|
||||
</div>
|
||||
</div>
|
||||
</th:block>
|
||||
<th:block th:if="${showDownloadFactura}">
|
||||
<div class="col-12 col-md-auto">
|
||||
<div class="card card border mb-3">
|
||||
<div class="card-header bg-light">
|
||||
<span class="fs-16" th:text="#{'pedido.view.actions'}"></span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<button type="button" th:attr="data-factura-id=${facturaId}" class="btn btn-secondary w-100 btn-download-factura"
|
||||
th:text="#{pedido.view.descargar-factura}">
|
||||
Descargar factura
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</th:block>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<th:block th:each="linea: ${lineas}">
|
||||
<div
|
||||
th:insert="~{imprimelibros/pedidos/pedidos-linea :: pedido-linea (item=${linea}, isAdmin=${isAdmin})}">
|
||||
|
||||
107
src/main/resources/templates/imprimelibros/users/profile.html
Normal file
107
src/main/resources/templates/imprimelibros/users/profile.html
Normal file
@ -0,0 +1,107 @@
|
||||
<!doctype html>
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{imprimelibros/layout}">
|
||||
|
||||
<head>
|
||||
<th:block layout:fragment="pagetitle" />
|
||||
<th:block th:replace="~{imprimelibros/partials/head-css :: head-css}" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div th:replace="~{imprimelibros/partials/topbar :: topbar}" />
|
||||
<div th:replace="~{imprimelibros/partials/sidebar :: sidebar}" />
|
||||
|
||||
<th:block layout:fragment="content">
|
||||
<div th:if="${#authorization.expression('isAuthenticated()')}">
|
||||
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/"><i class="ri-home-5-fill"></i></a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page" th:text="#{app.perfil}">Perfil</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-12 col-lg-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0" th:text="#{usuarios.profile.title}">Editar perfil</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<div th:if="${success}" class="alert alert-success"
|
||||
th:text="#{usuarios.profile.success}">Perfil actualizado.</div>
|
||||
|
||||
<form id="profileForm" novalidate th:action="@{/pages-profile}" th:object="${user}"
|
||||
method="post">
|
||||
|
||||
<div th:if="${#fields.hasGlobalErrors()}" class="alert alert-danger">
|
||||
<div th:each="e : ${#fields.globalErrors()}" th:text="${e}"></div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label th:text="#{usuarios.form.nombre}" for="fullName">Nombre</label>
|
||||
<input type="text" class="form-control" id="fullName" th:field="*{fullName}"
|
||||
th:classappend="${#fields.hasErrors('fullName')} ? ' is-invalid'" required>
|
||||
<div class="invalid-feedback" th:if="${#fields.hasErrors('fullName')}"
|
||||
th:errors="*{fullName}">Error</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label th:text="#{usuarios.form.email}" for="userName">Correo electrónico</label>
|
||||
<input type="email" class="form-control" id="userName" th:field="*{userName}"
|
||||
th:classappend="${#fields.hasErrors('userName')} ? ' is-invalid'" required>
|
||||
<div class="invalid-feedback" th:if="${#fields.hasErrors('userName')}"
|
||||
th:errors="*{userName}">Error</div>
|
||||
</div>
|
||||
|
||||
<hr class="my-4">
|
||||
|
||||
<div class="mb-3">
|
||||
<label th:text="#{usuarios.form.password.actual}" for="currentPassword">Contraseña actual</label>
|
||||
<input type="password" class="form-control" id="currentPassword"
|
||||
th:field="*{currentPassword}"
|
||||
th:classappend="${#fields.hasErrors('currentPassword')} ? ' is-invalid'">
|
||||
<div class="invalid-feedback" th:if="${#fields.hasErrors('currentPassword')}"
|
||||
th:errors="*{currentPassword}">Error</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label th:text="#{usuarios.form.password.nueva}" for="newPassword">Nueva contraseña</label>
|
||||
<input type="password" class="form-control" id="newPassword"
|
||||
th:field="*{newPassword}"
|
||||
th:classappend="${#fields.hasErrors('newPassword')} ? ' is-invalid'">
|
||||
<div class="text-muted" th:text="#{usuarios.form.password.nota}">
|
||||
Solo podrás cambiar la contraseña si indicas la actual.
|
||||
</div>
|
||||
<div class="invalid-feedback" th:if="${#fields.hasErrors('newPassword')}"
|
||||
th:errors="*{newPassword}">Error</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label th:text="#{usuarios.form.confirmarPassword}" for="confirmPassword">Confirmar contraseña</label>
|
||||
<input type="password" class="form-control" id="confirmPassword"
|
||||
th:field="*{confirmPassword}"
|
||||
th:classappend="${#fields.hasErrors('confirmPassword')} ? ' is-invalid'">
|
||||
<div class="invalid-feedback" th:if="${#fields.hasErrors('confirmPassword')}"
|
||||
th:errors="*{confirmPassword}">Error</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
<button type="submit" class="btn btn-secondary" th:text="#{app.guardar}">Guardar</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</th:block>
|
||||
|
||||
<th:block layout:fragment="modal" />
|
||||
<th:block th:replace="~{theme/partials/vendor-scripts :: scripts}" />
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user