From 1ff4aff4bfb405eea9bd6f509a36317382b42116 Mon Sep 17 00:00:00 2001 From: julien gourmet Date: Mon, 20 Oct 2025 18:51:13 +0200 Subject: [PATCH 1/6] feat(seeding): add sample data for efficient testing - Insert 50 clients (35 ACTIVE, 15 DELETED) - Insert 175 contracts (60% END_DATE=NULL for ACTIVE) - Ensure DELETED contracts respect client DELETED_AT dates --- .../apifactory/seed/ManualDataSeeder.java | 50 ++++ src/main/resources/application.properties | 3 +- src/main/resources/data.sql | 237 ++++++++++++++++++ 3 files changed, 289 insertions(+), 1 deletion(-) create mode 100644 src/main/java/julien/gourmet/apifactory/seed/ManualDataSeeder.java create mode 100644 src/main/resources/data.sql diff --git a/src/main/java/julien/gourmet/apifactory/seed/ManualDataSeeder.java b/src/main/java/julien/gourmet/apifactory/seed/ManualDataSeeder.java new file mode 100644 index 0000000..36f98a1 --- /dev/null +++ b/src/main/java/julien/gourmet/apifactory/seed/ManualDataSeeder.java @@ -0,0 +1,50 @@ +package julien.gourmet.apifactory.seed; + +import julien.gourmet.apifactory.repository.ClientRepository; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.CommandLineRunner; +import org.springframework.core.io.ClassPathResource; +import org.springframework.jdbc.datasource.init.ScriptUtils; +import org.springframework.stereotype.Component; + +import javax.sql.DataSource; +import java.sql.Connection; + +@Component +public class ManualDataSeeder implements CommandLineRunner { + + @Value("${app.seed-db:false}") + private boolean seedDb; + + private final DataSource dataSource; + private final ClientRepository clientRepository; + + public ManualDataSeeder(DataSource dataSource, ClientRepository clientRepository) { + this.dataSource = dataSource; + this.clientRepository = clientRepository; + } + + @Override + public void run(String... args) throws Exception { + if (!seedDb) { + System.out.println("DATA SEEDING DISABLED"); + System.out.println(" Set 'app.seed-db=true' in application.properties to enable"); + return; + } + long existingClients = clientRepository.count(); + if (existingClients > 0) { + System.out.println("SKIPPING SEEDING - Database already contains" + existingClients + " clients"); + return; + } + try (Connection conn = dataSource.getConnection()) { + ScriptUtils.executeSqlScript(conn, new ClassPathResource("data.sql")); + System.out.println("SEEDING COMPLETED SUCCESSFULLY!"); + System.out.println(" Inserted: 50 clients + 175 contracts"); + System.out.println(" Database ready for development and testing !"); + } + catch (Exception e) { + System.err.println("SEEDING FAILED: " + e.getMessage()); + throw e; + } + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 91e072a..a90ea56 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -5,4 +5,5 @@ spring.datasource.username=admin spring.datasource.password=Admin@123 spring.jpa.database-platform=org.hibernate.dialect.H2Dialect spring.h2.console.enabled=true -spring.jpa.hibernate.ddl-auto=update \ No newline at end of file +spring.jpa.hibernate.ddl-auto=update +app.seed-db=true \ No newline at end of file diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql new file mode 100644 index 0000000..0345cd0 --- /dev/null +++ b/src/main/resources/data.sql @@ -0,0 +1,237 @@ +-- ===================== +-- Clients +-- ===================== +INSERT INTO client (ID, NAME, EMAIL, PHONE, BIRTH_DATE, IDENTIFIER, CLIENT_TYPE, STATUS, DELETED_AT) +VALUES (1, 'Alice Dupont', 'alice@mail.ch', '+41791234501', '1990-05-15', NULL, 'PERSON', 'ACTIVE', NULL), + (2, 'Bob Martin', 'bob@mail.fr', '+41791234502', '1985-08-20', NULL, 'PERSON', 'ACTIVE', NULL), + (3, 'ACME Corp', 'contact@acme.com', '+41791234503', NULL, 'aaa-123', 'COMPANY', 'ACTIVE', NULL), + (4, 'Globex Inc', 'info@globex.net', '+41441234504', NULL, 'bbb-456', 'COMPANY', 'ACTIVE', NULL), + (5, 'Charlie Leroy', 'charlie@sample.org', '+41791234505', '2000-01-10', NULL, 'PERSON', 'DELETED', + '2024-12-31'), + (6, 'David Roche', 'david@domain.ch', '+41791234506', '1992-03-11', NULL, 'PERSON', 'ACTIVE', NULL), + (7, 'Eva Zimmer', 'eva@website.fr', '+33123456789', '1988-07-22', NULL, 'PERSON', 'ACTIVE', NULL), + (8, 'Fabrik AG', 'contact@fabrik.com', '+41791234508', NULL, 'ccc-789', 'COMPANY', 'DELETED', '2023-06-30'), + (9, 'Gilles Bernard', 'gilles@mail.ch', '+41791234509', '1995-09-05', NULL, 'PERSON', 'ACTIVE', NULL), + (10, 'Hugo Meier', 'hugo@domain.org', '+41791234510', '1980-12-12', NULL, 'PERSON', 'ACTIVE', NULL), + (11, 'Iris Dubois', 'iris@mail.fr', '+41791234511', '1991-04-25', NULL, 'PERSON', 'ACTIVE', NULL), + (12, 'Jean-Paul Leroy', 'jp@company.com', '+41791234512', '1975-10-02', NULL, 'PERSON', 'ACTIVE', NULL), + (13, 'Kraft GmbH', 'contact@kraft.net', '+41791234513', NULL, 'ddd-321', 'COMPANY', 'ACTIVE', NULL), + (14, 'Laura Meier', 'laura@mail.ch', '+41791234514', '1993-11-18', NULL, 'PERSON', 'ACTIVE', NULL), + (15, 'Marc Petit', 'marc@domain.org', '+41791234515', '1987-01-09', NULL, 'PERSON', 'DELETED', '2025-01-15'), + (16, 'NanoTech SA', 'contact@nanotech.com', '+41791234516', NULL, 'eee-654', 'COMPANY', 'ACTIVE', NULL), + (17, 'Olivia Morel', 'olivia@mail.fr', '+41791234517', '1994-06-12', NULL, 'PERSON', 'ACTIVE', NULL), + (18, 'Pierre Durand', 'pierre@sample.ch', '+41791234518', '1982-03-03', NULL, 'PERSON', 'ACTIVE', NULL), + (19, 'Quantum AG', 'info@quantum.net', '+41791234519', NULL, 'fff-987', 'COMPANY', 'ACTIVE', NULL), + (20, 'Romain Blanc', 'romain@mail.ch', '+41791234520', '1990-09-09', NULL, 'PERSON', 'ACTIVE', NULL), + (21, 'Sophie Keller', 'sophie@domain.fr', '+41791234521', '1986-07-07', NULL, 'PERSON', 'ACTIVE', NULL), + (22, 'TechCorp', 'contact@techcorp.com', '+41791234522', NULL, 'ggg-111', 'COMPANY', 'ACTIVE', NULL), + (23, 'Urs Steiner', 'urs@mail.ch', '+41791234523', '1979-02-19', NULL, 'PERSON', 'DELETED', '2023-09-01'), + (24, 'Valerie Müller', 'valerie@website.org', '+41791234524', '1984-05-15', NULL, 'PERSON', 'ACTIVE', NULL), + (25, 'WebSolutions', 'contact@websolutions.net', '+41791234525', NULL, 'hhh-222', 'COMPANY', 'ACTIVE', NULL), + (26, 'Xavier Dupont', 'xavier@mail.fr', '+41791234526', '1995-08-08', NULL, 'PERSON', 'ACTIVE', NULL), + (27, 'Yannick Berger', 'yannick@domain.ch', '+41791234527', '1989-11-11', NULL, 'PERSON', 'ACTIVE', NULL), + (28, 'Zenith SA', 'contact@zenith.com', '+41791234528', NULL, 'iii-333', 'COMPANY', 'DELETED', '2024-02-28'), + (29, 'Anaïs Morel', 'anais@mail.ch', '+41791234529', '1992-12-12', NULL, 'PERSON', 'ACTIVE', NULL), + (30, 'Bruno Petit', 'bruno@domain.org', '+41791234530', '1981-04-04', NULL, 'PERSON', 'ACTIVE', NULL), + (31, 'Celine Dubois', 'celine@website.fr', '+41791234531', '1990-01-01', NULL, 'PERSON', 'ACTIVE', NULL), + (32, 'Delta AG', 'contact@delta.net', '+41791234532', NULL, 'jjj-444', 'COMPANY', 'ACTIVE', NULL), + (33, 'Emilie Roche', 'emilie@mail.ch', '+41791234533', '1987-09-09', NULL, 'PERSON', 'ACTIVE', NULL), + (34, 'Fabien Morel', 'fabien@domain.fr', '+41791234534', '1993-02-02', NULL, 'PERSON', 'ACTIVE', NULL), + (35, 'GlobalTech', 'contact@globaltech.com', '+41791234535', NULL, 'kkk-555', 'COMPANY', 'ACTIVE', NULL), + (36, 'Hélène Berger', 'helene@mail.ch', '+41791234536', '1991-06-06', NULL, 'PERSON', 'ACTIVE', NULL), + (37, 'Igor Keller', 'igor@website.net', '+41791234537', '1985-05-05', NULL, 'PERSON', 'ACTIVE', NULL), + (38, 'Jade Blanc', 'jade@mail.fr', '+41791234538', '1994-07-07', NULL, 'PERSON', 'ACTIVE', NULL), + (39, 'Kilian Meier', 'kilian@domain.org', '+41791234539', '1988-08-08', NULL, 'PERSON', 'ACTIVE', NULL), + (40, 'Logic SA', 'contact@logic.com', '+41791234540', NULL, 'lll-666', 'COMPANY', 'ACTIVE', NULL), + (41, 'Marie Dubois', 'marie@mail.ch', '+41791234541', '1990-03-03', NULL, 'PERSON', 'ACTIVE', NULL), + (42, 'Nicolas Petit', 'nicolas@domain.fr', '+41791234542', '1986-12-12', NULL, 'PERSON', 'ACTIVE', NULL), + (43, 'Olivier Morel', 'olivier@sample.org', '+41791234543', '1992-02-02', NULL, 'PERSON', 'ACTIVE', NULL), + (44, 'Paul Zimmer', 'paul@website.net', '+41791234544', '1983-07-07', NULL, 'PERSON', 'ACTIVE', NULL), + (45, 'Quentin Berger', 'quentin@mail.ch', '+41791234545', '1989-09-09', NULL, 'PERSON', 'ACTIVE', NULL), + (46, 'Rita Müller', 'rita@domain.fr', '+41791234546', '1991-11-11', NULL, 'PERSON', 'ACTIVE', NULL), + (47, 'Sigma AG', 'contact@sigma.com', '+41791234547', NULL, 'mmm-777', 'COMPANY', 'ACTIVE', NULL), + (48, 'Thomas Dupont', 'thomas@mail.ch', '+41791234548', '1987-03-03', NULL, 'PERSON', 'DELETED', '2025-05-31'), + (49, 'Ulrike Keller', 'ulrike@domain.net', '+41791234549', '1990-08-08', NULL, 'PERSON', 'ACTIVE', NULL), + (50, 'Vincent Meier', 'vincent@website.org', '+41791234550', '1985-06-06', NULL, 'PERSON', 'ACTIVE', NULL); + + +-- ===================== +-- Contracts +-- ===================== + +INSERT INTO contract (ID, COST_AMOUNT, CREATED_AT, START_DATE, END_DATE, UPDATED_AT, CLIENT_ID) +VALUES (1, 1250.00, '2023-01-15', '2023-02-01', NULL, '2025-10-20', 1), + (2, 890.50, '2023-03-10', '2023-04-01', NULL, '2025-10-20', 2), + (3, 2100.00, '2023-05-05', '2023-06-01', NULL, '2025-10-20', 6), + (4, 750.75, '2023-07-20', '2023-08-01', NULL, '2025-10-20', 7), + (5, 1450.25, '2023-09-12', '2023-10-01', NULL, '2025-10-20', 9), + (6, 980.00, '2023-11-08', '2023-12-01', NULL, '2025-10-20', 10), + (7, 1675.50, '2024-01-25', '2024-02-01', NULL, '2025-10-20', 11), + (8, 1120.00, '2024-03-18', '2024-04-01', '2026-03-31', '2025-10-20', 12), + (9, 650.00, '2024-05-30', '2024-06-01', NULL, '2025-10-20', 14), + (10, 1890.75, '2024-07-15', '2024-08-01', NULL, '2025-10-20', 17), + (11, 920.25, '2024-09-22', '2024-10-01', NULL, '2025-10-20', 18), + (12, 2340.00, '2024-11-10', '2024-12-01', '2026-11-30', '2025-10-20', 20), + (13, 780.50, '2025-01-05', '2025-02-01', NULL, '2025-10-20', 21), + (14, 1560.00, '2025-03-12', '2025-04-01', NULL, '2025-10-20', 24), + (15, 890.00, '2025-05-20', '2025-06-01', NULL, '2025-10-20', 26), + (16, 2100.25, '2025-07-08', '2025-08-01', '2027-07-31', '2025-10-20', 27), + (17, 1345.75, '2025-09-15', '2025-10-01', NULL, '2025-10-20', 29), + (18, 1670.00, '2023-02-28', '2023-03-01', NULL, '2025-10-20', 30), + (19, 980.50, '2023-04-15', '2023-05-01', NULL, '2025-10-20', 31), + (20, 2450.00, '2023-06-10', '2023-07-01', '2025-06-30', '2025-10-20', 33), + (21, 720.25, '2023-08-25', '2023-09-01', NULL, '2025-10-20', 34), + (22, 1890.75, '2023-10-20', '2023-11-01', NULL, '2025-10-20', 36), + (23, 1125.00, '2024-01-12', '2024-02-01', NULL, '2025-10-20', 37), + (24, 1560.50, '2024-03-05', '2024-04-01', '2026-03-31', '2025-10-20', 38), + (25, 890.00, '2024-05-18', '2024-06-01', NULL, '2025-10-20', 39), + (26, 2230.25, '2024-07-30', '2024-08-01', NULL, '2025-10-20', 41), + (27, 1450.75, '2024-09-22', '2024-10-01', NULL, '2025-10-20', 42), + (28, 1780.00, '2025-01-15', '2025-02-01', '2027-01-31', '2025-10-20', 43), + (29, 920.50, '2025-03-10', '2025-04-01', NULL, '2025-10-20', 44), + (30, 2010.00, '2025-05-05', '2025-06-01', NULL, '2025-10-20', 45), + (31, 1340.25, '2025-07-20', '2025-08-01', NULL, '2025-10-20', 46), + (32, 1675.50, '2025-09-12', '2025-10-01', '2027-09-30', '2025-10-20', 49), + (33, 890.00, '2023-01-08', '2023-02-01', NULL, '2025-10-20', 50), + (51, 1200.00, '2023-12-15', '2024-01-01', NULL, '2025-10-20', 1), + (52, 950.25, '2024-02-20', '2024-03-01', NULL, '2025-10-20', 2), + (53, 1780.50, '2024-04-12', '2024-05-01', NULL, '2025-10-20', 6), + (54, 680.00, '2024-06-25', '2024-07-01', NULL, '2025-10-20', 7), + (55, 1980.75, '2024-08-18', '2024-09-01', NULL, '2025-10-20', 9), + (56, 1050.00, '2025-01-10', '2025-02-01', NULL, '2025-10-20', 10), + (57, 2340.25, '2025-03-05', '2025-04-01', '2027-03-31', '2025-10-20', 11), + (58, 1450.50, '2025-05-22', '2025-06-01', NULL, '2025-10-20', 12), + (59, 890.00, '2023-06-15', '2023-07-01', NULL, '2025-10-20', 14), + (60, 1670.75, '2023-08-20', '2023-09-01', NULL, '2025-10-20', 17), + (61, 2100.00, '2023-10-12', '2023-11-01', NULL, '2025-10-20', 18), + (62, 780.25, '2024-01-25', '2024-02-01', NULL, '2025-10-20', 20), + (63, 1890.50, '2024-03-30', '2024-04-01', '2026-03-31', '2025-10-20', 21), + (64, 1340.00, '2024-05-15', '2024-06-01', NULL, '2025-10-20', 24), + (65, 1560.75, '2024-07-20', '2024-08-01', NULL, '2025-10-20', 26), + (66, 920.00, '2025-01-12', '2025-02-01', NULL, '2025-10-20', 27), + (67, 2230.25, '2025-03-18', '2025-04-01', NULL, '2025-10-20', 29), + (68, 1450.50, '2025-05-10', '2025-06-01', NULL, '2025-10-20', 30), + (69, 1780.00, '2025-07-25', '2025-08-01', '2027-07-31', '2025-10-20', 31), + (70, 980.75, '2023-04-08', '2023-05-01', NULL, '2025-10-20', 33), + (81, 1200.00, '2023-11-10', '2023-12-01', NULL, '2025-10-20', 34), + (82, 1670.25, '2024-02-15', '2024-03-01', NULL, '2025-10-20', 36), + (83, 890.50, '2024-04-20', '2024-05-01', NULL, '2025-10-20', 37), + (84, 2340.00, '2024-06-12', '2024-07-01', '2027-06-30', '2025-10-20', 38), + (85, 980.75, '2024-08-25', '2024-09-01', NULL, '2025-10-20', 39), + (86, 1890.00, '2025-01-18', '2025-02-01', NULL, '2025-10-20', 41), + (87, 1450.25, '2025-03-10', '2025-04-01', NULL, '2025-10-20', 42), + (88, 2100.50, '2025-05-22', '2025-06-01', '2027-05-31', '2025-10-20', 43), + (89, 780.00, '2025-07-15', '2025-08-01', NULL, '2025-10-20', 44), + (90, 1560.75, '2025-09-20', '2025-10-01', NULL, '2025-10-20', 45), + (91, 1340.00, '2023-03-12', '2023-04-01', NULL, '2025-10-20', 46), + (92, 1780.25, '2023-05-25', '2023-06-01', NULL, '2025-10-20', 49), + (93, 920.50, '2023-07-20', '2023-08-01', NULL, '2025-10-20', 50), + (94, 2230.00, '2023-09-15', '2023-10-01', NULL, '2025-10-20', 1), + (95, 1450.75, '2024-01-10', '2024-02-01', '2026-01-31', '2025-10-20', 2), + (96, 1890.00, '2024-03-22', '2024-04-01', NULL, '2025-10-20', 6), + (97, 780.25, '2024-05-15', '2024-06-01', NULL, '2025-10-20', 7), + (98, 2100.50, '2024-07-30', '2024-08-01', NULL, '2025-10-20', 9), + (99, 1340.00, '2025-01-12', '2025-02-01', NULL, '2025-10-20', 10), + (100, 1670.75, '2025-03-18', '2025-04-01', NULL, '2025-10-20', 11), + (101, 890.00, '2025-05-10', '2025-06-01', NULL, '2025-10-20', 12), + (102, 2340.25, '2025-07-25', '2025-08-01', '2028-07-31', '2025-10-20', 14), + (103, 980.50, '2023-02-20', '2023-03-01', NULL, '2025-10-20', 17), + (104, 1560.00, '2023-04-15', '2023-05-01', NULL, '2025-10-20', 18), + (105, 1890.75, '2023-06-22', '2023-07-01', NULL, '2025-10-20', 20), + (106, 1200.00, '2023-08-10', '2023-09-01', NULL, '2025-10-20', 21), + (107, 1450.25, '2024-01-25', '2024-02-01', '2026-01-31', '2025-10-20', 24), + (108, 2100.50, '2024-03-20', '2024-04-01', NULL, '2025-10-20', 26), + (109, 780.00, '2024-05-12', '2024-06-01', NULL, '2025-10-20', 27), + (110, 1670.75, '2024-07-30', '2024-08-01', NULL, '2025-10-20', 29), + (111, 2340.00, '2025-01-15', '2025-02-01', '2027-01-31', '2025-10-20', 30), + (112, 890.25, '2025-03-22', '2025-04-01', NULL, '2025-10-20', 31), + (113, 1980.50, '2025-05-15', '2025-06-01', NULL, '2025-10-20', 33), + (114, 1340.00, '2025-07-20', '2025-08-01', NULL, '2025-10-20', 34), + (115, 1560.75, '2023-10-25', '2023-11-01', NULL, '2025-10-20', 36), + (116, 920.00, '2024-01-12', '2024-02-01', NULL, '2025-10-20', 37), + (117, 2230.25, '2024-03-18', '2024-04-01', NULL, '2025-10-20', 38), + (118, 1450.50, '2024-05-25', '2024-06-01', NULL, '2025-10-20', 39), + (119, 1890.00, '2024-07-20', '2024-08-01', '2027-07-31', '2025-10-20', 41), + (120, 780.75, '2025-01-10', '2025-02-01', NULL, '2025-10-20', 42), + (121, 2100.00, '2025-03-22', '2025-04-01', NULL, '2025-10-20', 43), + (122, 1340.25, '2025-05-15', '2025-06-01', NULL, '2025-10-20', 44), + (123, 1670.50, '2025-07-30', '2025-08-01', '2027-07-31', '2025-10-20', 45), + (124, 890.00, '2023-05-12', '2023-06-01', NULL, '2025-10-20', 46), + (125, 2340.75, '2023-07-25', '2023-08-01', NULL, '2025-10-20', 49), + (126, 980.00, '2024-01-20', '2024-02-01', NULL, '2025-10-20', 50), + (127, 1560.25, '2024-03-15', '2024-04-01', NULL, '2025-10-20', 1), + (128, 1890.50, '2024-05-22', '2024-06-01', NULL, '2025-10-20', 2), + (129, 1200.00, '2024-07-18', '2024-08-01', NULL, '2025-10-20', 6), + (130, 1450.75, '2025-01-12', '2025-02-01', '2027-01-31', '2025-10-20', 7), + (131, 2100.00, '2025-03-25', '2025-04-01', NULL, '2025-10-20', 9), + (132, 780.25, '2025-05-20', '2025-06-01', NULL, '2025-10-20', 10), + (133, 1670.50, '2023-08-15', '2023-09-01', NULL, '2025-10-20', 11), + (134, 2340.00, '2023-10-22', '2023-11-01', NULL, '2025-10-20', 12), + (135, 890.75, '2024-01-15', '2024-02-01', NULL, '2025-10-20', 14), + (136, 1980.25, '2024-03-30', '2024-04-01', NULL, '2025-10-20', 17), + (137, 1340.50, '2024-05-25', '2024-06-01', NULL, '2025-10-20', 18), + (138, 1560.00, '2025-01-18', '2025-02-01', '2027-01-31', '2025-10-20', 20), + (139, 920.75, '2025-03-12', '2025-04-01', NULL, '2025-10-20', 21), + (140, 2230.00, '2025-05-25', '2025-06-01', NULL, '2025-10-20', 24), + (141, 1450.25, '2023-06-20', '2023-07-01', NULL, '2025-10-20', 26), + (142, 1890.50, '2023-08-15', '2023-09-01', NULL, '2025-10-20', 27), + (143, 780.00, '2024-01-22', '2024-02-01', NULL, '2025-10-20', 29), + (144, 2100.75, '2024-03-18', '2024-04-01', NULL, '2025-10-20', 30), + (145, 1340.00, '2024-05-12', '2024-06-01', NULL, '2025-10-20', 31), + (146, 1670.25, '2025-01-25', '2025-02-01', '2027-01-31', '2025-10-20', 33), + (147, 890.50, '2025-03-20', '2025-04-01', NULL, '2025-10-20', 34), + (148, 2340.00, '2025-05-15', '2025-06-01', NULL, '2025-10-20', 36), + (149, 980.75, '2025-07-22', '2025-08-01', NULL, '2025-10-20', 37), + (150, 1560.00, '2023-09-25', '2023-10-01', NULL, '2025-10-20', 38), + (151, 1890.25, '2024-01-15', '2024-02-01', NULL, '2025-10-20', 39), + (152, 1200.50, '2024-03-22', '2024-04-01', NULL, '2025-10-20', 41), + (153, 1450.00, '2024-05-18', '2024-06-01', '2027-05-31', '2025-10-20', 42), + (154, 2100.75, '2025-01-12', '2025-02-01', NULL, '2025-10-20', 43), + (155, 780.00, '2025-03-25', '2025-04-01', NULL, '2025-10-20', 44), + (156, 1670.25, '2025-05-20', '2025-06-01', NULL, '2025-10-20', 45), + (157, 2340.50, '2023-07-12', '2023-08-01', NULL, '2025-10-20', 46), + (158, 890.00, '2024-01-25', '2024-02-01', NULL, '2025-10-20', 49), + (159, 1980.75, '2024-03-20', '2024-04-01', NULL, '2025-10-20', 50), + (160, 1340.00, '2024-05-15', '2024-06-01', NULL, '2025-10-20', 1), + (161, 1560.25, '2025-01-22', '2025-02-01', NULL, '2025-10-20', 2), + (162, 920.50, '2025-03-18', '2025-04-01', NULL, '2025-10-20', 6), + (163, 2230.00, '2025-05-12', '2025-06-01', NULL, '2025-10-20', 7), + (164, 1450.75, '2023-10-15', '2023-11-01', NULL, '2025-10-20', 9), + (165, 1890.00, '2024-01-20', '2024-02-01', NULL, '2025-10-20', 10), + (166, 780.25, '2024-03-25', '2024-04-01', NULL, '2025-10-20', 11), + (167, 2100.50, '2024-05-22', '2024-06-01', NULL, '2025-10-20', 12), + (168, 1340.00, '2025-01-15', '2025-02-01', NULL, '2025-10-20', 14), + (169, 1670.75, '2025-03-30', '2025-04-01', NULL, '2025-10-20', 17), + (170, 890.00, '2025-05-25', '2025-06-01', NULL, '2025-10-20', 18), + (171, 2340.25, '2023-12-12', '2024-01-01', NULL, '2025-10-20', 20), + (172, 980.50, '2024-02-20', '2024-03-01', NULL, '2025-10-20', 21), + (173, 1560.00, '2024-04-15', '2024-05-01', NULL, '2025-10-20', 24), + (174, 1890.75, '2024-06-22', '2024-07-01', NULL, '2025-10-20', 26), + (175, 1200.00, '2025-01-18', '2025-02-01', NULL, '2025-10-20', 27), + (34, 4500.00, '2023-02-15', '2023-03-01', NULL, '2025-10-20', 3), + (35, 7800.25, '2023-04-10', '2023-05-01', '2026-04-30', '2025-10-20', 4), + (36, 3200.50, '2023-06-25', '2023-07-01', NULL, '2025-10-20', 13), + (37, 8900.00, '2023-08-20', '2023-09-01', NULL, '2025-10-20', 16), + (38, 5600.75, '2023-10-15', '2023-11-01', NULL, '2025-10-20', 19), + (39, 4100.00, '2024-01-05', '2024-02-01', NULL, '2025-10-20', 22), + (40, 6700.25, '2024-03-12', '2024-04-01', '2027-03-31', '2025-10-20', 25), + (41, 2900.50, '2024-05-30', '2024-06-01', NULL, '2025-10-20', 32), + (42, 8500.00, '2024-07-25', '2024-08-01', NULL, '2025-10-20', 35), + (43, 3800.75, '2024-09-20', '2024-10-01', NULL, '2025-10-20', 40), + (44, 7200.00, '2025-01-15', '2025-02-01', NULL, '2025-10-20', 47), + (71, 5600.00, '2023-05-20', '2023-06-01', NULL, '2025-10-20', 3), + (72, 9200.25, '2023-07-15', '2023-08-01', '2027-07-31', '2025-10-20', 4), + (73, 3400.50, '2023-09-25', '2023-10-01', NULL, '2025-10-20', 13), + (74, 7800.00, '2024-01-20', '2024-02-01', NULL, '2025-10-20', 16), + (75, 4500.75, '2024-03-12', '2024-04-01', NULL, '2025-10-20', 19), + (76, 2900.00, '2024-05-30', '2024-06-01', NULL, '2025-10-20', 22), + (77, 6800.25, '2024-07-25', '2024-08-01', '2028-07-31', '2025-10-20', 25), + (78, 3100.50, '2025-01-15', '2025-02-01', NULL, '2025-10-20', 32), + (79, 9400.00, '2025-03-20', '2025-04-01', NULL, '2025-10-20', 35), + (80, 4200.75, '2025-05-12', '2025-06-01', NULL, '2025-10-20', 40), + (45, 980.00, '2023-05-01', '2023-06-01', '2024-12-31', '2024-12-31', 5), + (46, 2100.50, '2023-07-10', '2023-08-01', '2023-06-30', '2023-06-30', 8), + (47, 1450.25, '2024-02-15', '2024-03-01', '2025-01-15', '2025-01-15', 15), + (48, 890.75, '2023-03-20', '2023-04-01', '2023-09-01', '2023-09-01', 23), + (49, 1670.00, '2024-08-10', '2024-09-01', '2024-02-28', '2024-02-28', 28), + (50, 2340.50, '2025-03-05', '2025-04-01', '2025-05-31', '2025-05-31', 48); \ No newline at end of file From 6afba46f447dcdcaaaabe58c1d783e6f634dbe79 Mon Sep 17 00:00:00 2001 From: julien gourmet Date: Mon, 20 Oct 2025 18:59:16 +0200 Subject: [PATCH 2/6] fix(tests): disable seeding in test profile - Add @Profile("!test") to ManualDataSeeder - Set app.seed-db=false in application-test.properties - Set app.seed-db=false in application.properties - Set spring.sql.init.mode=never in application-test.properties --- .../java/julien/gourmet/apifactory/seed/ManualDataSeeder.java | 2 ++ src/main/resources/application.properties | 2 +- src/test/resources/application-test.properties | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/julien/gourmet/apifactory/seed/ManualDataSeeder.java b/src/main/java/julien/gourmet/apifactory/seed/ManualDataSeeder.java index 36f98a1..847e6a9 100644 --- a/src/main/java/julien/gourmet/apifactory/seed/ManualDataSeeder.java +++ b/src/main/java/julien/gourmet/apifactory/seed/ManualDataSeeder.java @@ -3,6 +3,7 @@ import julien.gourmet.apifactory.repository.ClientRepository; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.CommandLineRunner; +import org.springframework.context.annotation.Profile; import org.springframework.core.io.ClassPathResource; import org.springframework.jdbc.datasource.init.ScriptUtils; import org.springframework.stereotype.Component; @@ -11,6 +12,7 @@ import java.sql.Connection; @Component +@Profile("!test") public class ManualDataSeeder implements CommandLineRunner { @Value("${app.seed-db:false}") diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index a90ea56..824664b 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -6,4 +6,4 @@ spring.datasource.password=Admin@123 spring.jpa.database-platform=org.hibernate.dialect.H2Dialect spring.h2.console.enabled=true spring.jpa.hibernate.ddl-auto=update -app.seed-db=true \ No newline at end of file +app.seed-db=false \ No newline at end of file diff --git a/src/test/resources/application-test.properties b/src/test/resources/application-test.properties index b2739cf..9a6a7d6 100644 --- a/src/test/resources/application-test.properties +++ b/src/test/resources/application-test.properties @@ -6,3 +6,5 @@ spring.datasource.password= spring.jpa.database-platform=org.hibernate.dialect.H2Dialect spring.jpa.hibernate.ddl-auto=create-drop spring.h2.console.enabled=false +app.seed-db=false +spring.sql.init.mode=never From ec3cb9fc013e0faf63148641fb829d9b0750e6e9 Mon Sep 17 00:00:00 2001 From: julien gourmet Date: Tue, 21 Oct 2025 16:50:21 +0200 Subject: [PATCH 3/6] fix(seed): update data.sql, remove fixed index. --- src/main/resources/data.sql | 462 ++++++++++++++++++------------------ 1 file changed, 231 insertions(+), 231 deletions(-) diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 0345cd0..76bab78 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -1,237 +1,237 @@ -- ===================== --- Clients +-- Clients (SANS ID fixes → génération automatique) -- ===================== -INSERT INTO client (ID, NAME, EMAIL, PHONE, BIRTH_DATE, IDENTIFIER, CLIENT_TYPE, STATUS, DELETED_AT) -VALUES (1, 'Alice Dupont', 'alice@mail.ch', '+41791234501', '1990-05-15', NULL, 'PERSON', 'ACTIVE', NULL), - (2, 'Bob Martin', 'bob@mail.fr', '+41791234502', '1985-08-20', NULL, 'PERSON', 'ACTIVE', NULL), - (3, 'ACME Corp', 'contact@acme.com', '+41791234503', NULL, 'aaa-123', 'COMPANY', 'ACTIVE', NULL), - (4, 'Globex Inc', 'info@globex.net', '+41441234504', NULL, 'bbb-456', 'COMPANY', 'ACTIVE', NULL), - (5, 'Charlie Leroy', 'charlie@sample.org', '+41791234505', '2000-01-10', NULL, 'PERSON', 'DELETED', - '2024-12-31'), - (6, 'David Roche', 'david@domain.ch', '+41791234506', '1992-03-11', NULL, 'PERSON', 'ACTIVE', NULL), - (7, 'Eva Zimmer', 'eva@website.fr', '+33123456789', '1988-07-22', NULL, 'PERSON', 'ACTIVE', NULL), - (8, 'Fabrik AG', 'contact@fabrik.com', '+41791234508', NULL, 'ccc-789', 'COMPANY', 'DELETED', '2023-06-30'), - (9, 'Gilles Bernard', 'gilles@mail.ch', '+41791234509', '1995-09-05', NULL, 'PERSON', 'ACTIVE', NULL), - (10, 'Hugo Meier', 'hugo@domain.org', '+41791234510', '1980-12-12', NULL, 'PERSON', 'ACTIVE', NULL), - (11, 'Iris Dubois', 'iris@mail.fr', '+41791234511', '1991-04-25', NULL, 'PERSON', 'ACTIVE', NULL), - (12, 'Jean-Paul Leroy', 'jp@company.com', '+41791234512', '1975-10-02', NULL, 'PERSON', 'ACTIVE', NULL), - (13, 'Kraft GmbH', 'contact@kraft.net', '+41791234513', NULL, 'ddd-321', 'COMPANY', 'ACTIVE', NULL), - (14, 'Laura Meier', 'laura@mail.ch', '+41791234514', '1993-11-18', NULL, 'PERSON', 'ACTIVE', NULL), - (15, 'Marc Petit', 'marc@domain.org', '+41791234515', '1987-01-09', NULL, 'PERSON', 'DELETED', '2025-01-15'), - (16, 'NanoTech SA', 'contact@nanotech.com', '+41791234516', NULL, 'eee-654', 'COMPANY', 'ACTIVE', NULL), - (17, 'Olivia Morel', 'olivia@mail.fr', '+41791234517', '1994-06-12', NULL, 'PERSON', 'ACTIVE', NULL), - (18, 'Pierre Durand', 'pierre@sample.ch', '+41791234518', '1982-03-03', NULL, 'PERSON', 'ACTIVE', NULL), - (19, 'Quantum AG', 'info@quantum.net', '+41791234519', NULL, 'fff-987', 'COMPANY', 'ACTIVE', NULL), - (20, 'Romain Blanc', 'romain@mail.ch', '+41791234520', '1990-09-09', NULL, 'PERSON', 'ACTIVE', NULL), - (21, 'Sophie Keller', 'sophie@domain.fr', '+41791234521', '1986-07-07', NULL, 'PERSON', 'ACTIVE', NULL), - (22, 'TechCorp', 'contact@techcorp.com', '+41791234522', NULL, 'ggg-111', 'COMPANY', 'ACTIVE', NULL), - (23, 'Urs Steiner', 'urs@mail.ch', '+41791234523', '1979-02-19', NULL, 'PERSON', 'DELETED', '2023-09-01'), - (24, 'Valerie Müller', 'valerie@website.org', '+41791234524', '1984-05-15', NULL, 'PERSON', 'ACTIVE', NULL), - (25, 'WebSolutions', 'contact@websolutions.net', '+41791234525', NULL, 'hhh-222', 'COMPANY', 'ACTIVE', NULL), - (26, 'Xavier Dupont', 'xavier@mail.fr', '+41791234526', '1995-08-08', NULL, 'PERSON', 'ACTIVE', NULL), - (27, 'Yannick Berger', 'yannick@domain.ch', '+41791234527', '1989-11-11', NULL, 'PERSON', 'ACTIVE', NULL), - (28, 'Zenith SA', 'contact@zenith.com', '+41791234528', NULL, 'iii-333', 'COMPANY', 'DELETED', '2024-02-28'), - (29, 'Anaïs Morel', 'anais@mail.ch', '+41791234529', '1992-12-12', NULL, 'PERSON', 'ACTIVE', NULL), - (30, 'Bruno Petit', 'bruno@domain.org', '+41791234530', '1981-04-04', NULL, 'PERSON', 'ACTIVE', NULL), - (31, 'Celine Dubois', 'celine@website.fr', '+41791234531', '1990-01-01', NULL, 'PERSON', 'ACTIVE', NULL), - (32, 'Delta AG', 'contact@delta.net', '+41791234532', NULL, 'jjj-444', 'COMPANY', 'ACTIVE', NULL), - (33, 'Emilie Roche', 'emilie@mail.ch', '+41791234533', '1987-09-09', NULL, 'PERSON', 'ACTIVE', NULL), - (34, 'Fabien Morel', 'fabien@domain.fr', '+41791234534', '1993-02-02', NULL, 'PERSON', 'ACTIVE', NULL), - (35, 'GlobalTech', 'contact@globaltech.com', '+41791234535', NULL, 'kkk-555', 'COMPANY', 'ACTIVE', NULL), - (36, 'Hélène Berger', 'helene@mail.ch', '+41791234536', '1991-06-06', NULL, 'PERSON', 'ACTIVE', NULL), - (37, 'Igor Keller', 'igor@website.net', '+41791234537', '1985-05-05', NULL, 'PERSON', 'ACTIVE', NULL), - (38, 'Jade Blanc', 'jade@mail.fr', '+41791234538', '1994-07-07', NULL, 'PERSON', 'ACTIVE', NULL), - (39, 'Kilian Meier', 'kilian@domain.org', '+41791234539', '1988-08-08', NULL, 'PERSON', 'ACTIVE', NULL), - (40, 'Logic SA', 'contact@logic.com', '+41791234540', NULL, 'lll-666', 'COMPANY', 'ACTIVE', NULL), - (41, 'Marie Dubois', 'marie@mail.ch', '+41791234541', '1990-03-03', NULL, 'PERSON', 'ACTIVE', NULL), - (42, 'Nicolas Petit', 'nicolas@domain.fr', '+41791234542', '1986-12-12', NULL, 'PERSON', 'ACTIVE', NULL), - (43, 'Olivier Morel', 'olivier@sample.org', '+41791234543', '1992-02-02', NULL, 'PERSON', 'ACTIVE', NULL), - (44, 'Paul Zimmer', 'paul@website.net', '+41791234544', '1983-07-07', NULL, 'PERSON', 'ACTIVE', NULL), - (45, 'Quentin Berger', 'quentin@mail.ch', '+41791234545', '1989-09-09', NULL, 'PERSON', 'ACTIVE', NULL), - (46, 'Rita Müller', 'rita@domain.fr', '+41791234546', '1991-11-11', NULL, 'PERSON', 'ACTIVE', NULL), - (47, 'Sigma AG', 'contact@sigma.com', '+41791234547', NULL, 'mmm-777', 'COMPANY', 'ACTIVE', NULL), - (48, 'Thomas Dupont', 'thomas@mail.ch', '+41791234548', '1987-03-03', NULL, 'PERSON', 'DELETED', '2025-05-31'), - (49, 'Ulrike Keller', 'ulrike@domain.net', '+41791234549', '1990-08-08', NULL, 'PERSON', 'ACTIVE', NULL), - (50, 'Vincent Meier', 'vincent@website.org', '+41791234550', '1985-06-06', NULL, 'PERSON', 'ACTIVE', NULL); +INSERT INTO client (NAME, EMAIL, PHONE, BIRTH_DATE, IDENTIFIER, CLIENT_TYPE, STATUS, DELETED_AT) +VALUES + ('Alice Dupont', 'alice@mail.ch', '+41791234501', '1990-05-15', NULL, 'PERSON', 'ACTIVE', NULL), + ('Bob Martin', 'bob@mail.fr', '+41791234502', '1985-08-20', NULL, 'PERSON', 'ACTIVE', NULL), + ('ACME Corp', 'contact@acme.com', '+41791234503', NULL, 'aaa-123', 'COMPANY', 'ACTIVE', NULL), + ('Globex Inc', 'info@globex.net', '+41441234504', NULL, 'bbb-456', 'COMPANY', 'ACTIVE', NULL), + ('Charlie Leroy', 'charlie@sample.org', '+41791234505', '2000-01-10', NULL, 'PERSON', 'DELETED', '2024-12-31'), + ('David Roche', 'david@domain.ch', '+41791234506', '1992-03-11', NULL, 'PERSON', 'ACTIVE', NULL), + ('Eva Zimmer', 'eva@website.fr', '+33123456789', '1988-07-22', NULL, 'PERSON', 'ACTIVE', NULL), + ('Fabrik AG', 'contact@fabrik.com', '+41791234508', NULL, 'ccc-789', 'COMPANY', 'DELETED', '2023-06-30'), + ('Gilles Bernard', 'gilles@mail.ch', '+41791234509', '1995-09-05', NULL, 'PERSON', 'ACTIVE', NULL), + ('Hugo Meier', 'hugo@domain.org', '+41791234510', '1980-12-12', NULL, 'PERSON', 'ACTIVE', NULL), + ('Iris Dubois', 'iris@mail.fr', '+41791234511', '1991-04-25', NULL, 'PERSON', 'ACTIVE', NULL), + ('Jean-Paul Leroy', 'jp@company.com', '+41791234512', '1975-10-02', NULL, 'PERSON', 'ACTIVE', NULL), + ('Kraft GmbH', 'contact@kraft.net', '+41791234513', NULL, 'ddd-321', 'COMPANY', 'ACTIVE', NULL), + ('Laura Meier', 'laura@mail.ch', '+41791234514', '1993-11-18', NULL, 'PERSON', 'ACTIVE', NULL), + ('Marc Petit', 'marc@domain.org', '+41791234515', '1987-01-09', NULL, 'PERSON', 'DELETED', '2025-01-15'), + ('NanoTech SA', 'contact@nanotech.com', '+41791234516', NULL, 'eee-654', 'COMPANY', 'ACTIVE', NULL), + ('Olivia Morel', 'olivia@mail.fr', '+41791234517', '1994-06-12', NULL, 'PERSON', 'ACTIVE', NULL), + ('Pierre Durand', 'pierre@sample.ch', '+41791234518', '1982-03-03', NULL, 'PERSON', 'ACTIVE', NULL), + ('Quantum AG', 'info@quantum.net', '+41791234519', NULL, 'fff-987', 'COMPANY', 'ACTIVE', NULL), + ('Romain Blanc', 'romain@mail.ch', '+41791234520', '1990-09-09', NULL, 'PERSON', 'ACTIVE', NULL), + ('Sophie Keller', 'sophie@domain.fr', '+41791234521', '1986-07-07', NULL, 'PERSON', 'ACTIVE', NULL), + ('TechCorp', 'contact@techcorp.com', '+41791234522', NULL, 'ggg-111', 'COMPANY', 'ACTIVE', NULL), + ('Urs Steiner', 'urs@mail.ch', '+41791234523', '1979-02-19', NULL, 'PERSON', 'DELETED', '2023-09-01'), + ('Valerie Müller', 'valerie@website.org', '+41791234524', '1984-05-15', NULL, 'PERSON', 'ACTIVE', NULL), + ('WebSolutions', 'contact@websolutions.net', '+41791234525', NULL, 'hhh-222', 'COMPANY', 'ACTIVE', NULL), + ('Xavier Dupont', 'xavier@mail.fr', '+41791234526', '1995-08-08', NULL, 'PERSON', 'ACTIVE', NULL), + ('Yannick Berger', 'yannick@domain.ch', '+41791234527', '1989-11-11', NULL, 'PERSON', 'ACTIVE', NULL), + ('Zenith SA', 'contact@zenith.com', '+41791234528', NULL, 'iii-333', 'COMPANY', 'DELETED', '2024-02-28'), + ('Anaïs Morel', 'anais@mail.ch', '+41791234529', '1992-12-12', NULL, 'PERSON', 'ACTIVE', NULL), + ('Bruno Petit', 'bruno@domain.org', '+41791234530', '1981-04-04', NULL, 'PERSON', 'ACTIVE', NULL), + ('Celine Dubois', 'celine@website.fr', '+41791234531', '1990-01-01', NULL, 'PERSON', 'ACTIVE', NULL), + ('Delta AG', 'contact@delta.net', '+41791234532', NULL, 'jjj-444', 'COMPANY', 'ACTIVE', NULL), + ('Emilie Roche', 'emilie@mail.ch', '+41791234533', '1987-09-09', NULL, 'PERSON', 'ACTIVE', NULL), + ('Fabien Morel', 'fabien@domain.fr', '+41791234534', '1993-02-02', NULL, 'PERSON', 'ACTIVE', NULL), + ('GlobalTech', 'contact@globaltech.com', '+41791234535', NULL, 'kkk-555', 'COMPANY', 'ACTIVE', NULL), + ('Hélène Berger', 'helene@mail.ch', '+41791234536', '1991-06-06', NULL, 'PERSON', 'ACTIVE', NULL), + ('Igor Keller', 'igor@website.net', '+41791234537', '1985-05-05', NULL, 'PERSON', 'ACTIVE', NULL), + ('Jade Blanc', 'jade@mail.fr', '+41791234538', '1994-07-07', NULL, 'PERSON', 'ACTIVE', NULL), + ('Kilian Meier', 'kilian@domain.org', '+41791234539', '1988-08-08', NULL, 'PERSON', 'ACTIVE', NULL), + ('Logic SA', 'contact@logic.com', '+41791234540', NULL, 'lll-666', 'COMPANY', 'ACTIVE', NULL), + ('Marie Dubois', 'marie@mail.ch', '+41791234541', '1990-03-03', NULL, 'PERSON', 'ACTIVE', NULL), + ('Nicolas Petit', 'nicolas@domain.fr', '+41791234542', '1986-12-12', NULL, 'PERSON', 'ACTIVE', NULL), + ('Olivier Morel', 'olivier@sample.org', '+41791234543', '1992-02-02', NULL, 'PERSON', 'ACTIVE', NULL), + ('Paul Zimmer', 'paul@website.net', '+41791234544', '1983-07-07', NULL, 'PERSON', 'ACTIVE', NULL), + ('Quentin Berger', 'quentin@mail.ch', '+41791234545', '1989-09-09', NULL, 'PERSON', 'ACTIVE', NULL), + ('Rita Müller', 'rita@domain.fr', '+41791234546', '1991-11-11', NULL, 'PERSON', 'ACTIVE', NULL), + ('Sigma AG', 'contact@sigma.com', '+41791234547', NULL, 'mmm-777', 'COMPANY', 'ACTIVE', NULL), + ('Thomas Dupont', 'thomas@mail.ch', '+41791234548', '1987-03-03', NULL, 'PERSON', 'DELETED', '2025-05-31'), + ('Ulrike Keller', 'ulrike@domain.net', '+41791234549', '1990-08-08', NULL, 'PERSON', 'ACTIVE', NULL), + ('Vincent Meier', 'vincent@website.org', '+41791234550', '1985-06-06', NULL, 'PERSON', 'ACTIVE', NULL); -- ===================== --- Contracts +-- Contracts (avec CLIENT_ID fixes, ID générés automatiquement) -- ===================== - -INSERT INTO contract (ID, COST_AMOUNT, CREATED_AT, START_DATE, END_DATE, UPDATED_AT, CLIENT_ID) -VALUES (1, 1250.00, '2023-01-15', '2023-02-01', NULL, '2025-10-20', 1), - (2, 890.50, '2023-03-10', '2023-04-01', NULL, '2025-10-20', 2), - (3, 2100.00, '2023-05-05', '2023-06-01', NULL, '2025-10-20', 6), - (4, 750.75, '2023-07-20', '2023-08-01', NULL, '2025-10-20', 7), - (5, 1450.25, '2023-09-12', '2023-10-01', NULL, '2025-10-20', 9), - (6, 980.00, '2023-11-08', '2023-12-01', NULL, '2025-10-20', 10), - (7, 1675.50, '2024-01-25', '2024-02-01', NULL, '2025-10-20', 11), - (8, 1120.00, '2024-03-18', '2024-04-01', '2026-03-31', '2025-10-20', 12), - (9, 650.00, '2024-05-30', '2024-06-01', NULL, '2025-10-20', 14), - (10, 1890.75, '2024-07-15', '2024-08-01', NULL, '2025-10-20', 17), - (11, 920.25, '2024-09-22', '2024-10-01', NULL, '2025-10-20', 18), - (12, 2340.00, '2024-11-10', '2024-12-01', '2026-11-30', '2025-10-20', 20), - (13, 780.50, '2025-01-05', '2025-02-01', NULL, '2025-10-20', 21), - (14, 1560.00, '2025-03-12', '2025-04-01', NULL, '2025-10-20', 24), - (15, 890.00, '2025-05-20', '2025-06-01', NULL, '2025-10-20', 26), - (16, 2100.25, '2025-07-08', '2025-08-01', '2027-07-31', '2025-10-20', 27), - (17, 1345.75, '2025-09-15', '2025-10-01', NULL, '2025-10-20', 29), - (18, 1670.00, '2023-02-28', '2023-03-01', NULL, '2025-10-20', 30), - (19, 980.50, '2023-04-15', '2023-05-01', NULL, '2025-10-20', 31), - (20, 2450.00, '2023-06-10', '2023-07-01', '2025-06-30', '2025-10-20', 33), - (21, 720.25, '2023-08-25', '2023-09-01', NULL, '2025-10-20', 34), - (22, 1890.75, '2023-10-20', '2023-11-01', NULL, '2025-10-20', 36), - (23, 1125.00, '2024-01-12', '2024-02-01', NULL, '2025-10-20', 37), - (24, 1560.50, '2024-03-05', '2024-04-01', '2026-03-31', '2025-10-20', 38), - (25, 890.00, '2024-05-18', '2024-06-01', NULL, '2025-10-20', 39), - (26, 2230.25, '2024-07-30', '2024-08-01', NULL, '2025-10-20', 41), - (27, 1450.75, '2024-09-22', '2024-10-01', NULL, '2025-10-20', 42), - (28, 1780.00, '2025-01-15', '2025-02-01', '2027-01-31', '2025-10-20', 43), - (29, 920.50, '2025-03-10', '2025-04-01', NULL, '2025-10-20', 44), - (30, 2010.00, '2025-05-05', '2025-06-01', NULL, '2025-10-20', 45), - (31, 1340.25, '2025-07-20', '2025-08-01', NULL, '2025-10-20', 46), - (32, 1675.50, '2025-09-12', '2025-10-01', '2027-09-30', '2025-10-20', 49), - (33, 890.00, '2023-01-08', '2023-02-01', NULL, '2025-10-20', 50), - (51, 1200.00, '2023-12-15', '2024-01-01', NULL, '2025-10-20', 1), - (52, 950.25, '2024-02-20', '2024-03-01', NULL, '2025-10-20', 2), - (53, 1780.50, '2024-04-12', '2024-05-01', NULL, '2025-10-20', 6), - (54, 680.00, '2024-06-25', '2024-07-01', NULL, '2025-10-20', 7), - (55, 1980.75, '2024-08-18', '2024-09-01', NULL, '2025-10-20', 9), - (56, 1050.00, '2025-01-10', '2025-02-01', NULL, '2025-10-20', 10), - (57, 2340.25, '2025-03-05', '2025-04-01', '2027-03-31', '2025-10-20', 11), - (58, 1450.50, '2025-05-22', '2025-06-01', NULL, '2025-10-20', 12), - (59, 890.00, '2023-06-15', '2023-07-01', NULL, '2025-10-20', 14), - (60, 1670.75, '2023-08-20', '2023-09-01', NULL, '2025-10-20', 17), - (61, 2100.00, '2023-10-12', '2023-11-01', NULL, '2025-10-20', 18), - (62, 780.25, '2024-01-25', '2024-02-01', NULL, '2025-10-20', 20), - (63, 1890.50, '2024-03-30', '2024-04-01', '2026-03-31', '2025-10-20', 21), - (64, 1340.00, '2024-05-15', '2024-06-01', NULL, '2025-10-20', 24), - (65, 1560.75, '2024-07-20', '2024-08-01', NULL, '2025-10-20', 26), - (66, 920.00, '2025-01-12', '2025-02-01', NULL, '2025-10-20', 27), - (67, 2230.25, '2025-03-18', '2025-04-01', NULL, '2025-10-20', 29), - (68, 1450.50, '2025-05-10', '2025-06-01', NULL, '2025-10-20', 30), - (69, 1780.00, '2025-07-25', '2025-08-01', '2027-07-31', '2025-10-20', 31), - (70, 980.75, '2023-04-08', '2023-05-01', NULL, '2025-10-20', 33), - (81, 1200.00, '2023-11-10', '2023-12-01', NULL, '2025-10-20', 34), - (82, 1670.25, '2024-02-15', '2024-03-01', NULL, '2025-10-20', 36), - (83, 890.50, '2024-04-20', '2024-05-01', NULL, '2025-10-20', 37), - (84, 2340.00, '2024-06-12', '2024-07-01', '2027-06-30', '2025-10-20', 38), - (85, 980.75, '2024-08-25', '2024-09-01', NULL, '2025-10-20', 39), - (86, 1890.00, '2025-01-18', '2025-02-01', NULL, '2025-10-20', 41), - (87, 1450.25, '2025-03-10', '2025-04-01', NULL, '2025-10-20', 42), - (88, 2100.50, '2025-05-22', '2025-06-01', '2027-05-31', '2025-10-20', 43), - (89, 780.00, '2025-07-15', '2025-08-01', NULL, '2025-10-20', 44), - (90, 1560.75, '2025-09-20', '2025-10-01', NULL, '2025-10-20', 45), - (91, 1340.00, '2023-03-12', '2023-04-01', NULL, '2025-10-20', 46), - (92, 1780.25, '2023-05-25', '2023-06-01', NULL, '2025-10-20', 49), - (93, 920.50, '2023-07-20', '2023-08-01', NULL, '2025-10-20', 50), - (94, 2230.00, '2023-09-15', '2023-10-01', NULL, '2025-10-20', 1), - (95, 1450.75, '2024-01-10', '2024-02-01', '2026-01-31', '2025-10-20', 2), - (96, 1890.00, '2024-03-22', '2024-04-01', NULL, '2025-10-20', 6), - (97, 780.25, '2024-05-15', '2024-06-01', NULL, '2025-10-20', 7), - (98, 2100.50, '2024-07-30', '2024-08-01', NULL, '2025-10-20', 9), - (99, 1340.00, '2025-01-12', '2025-02-01', NULL, '2025-10-20', 10), - (100, 1670.75, '2025-03-18', '2025-04-01', NULL, '2025-10-20', 11), - (101, 890.00, '2025-05-10', '2025-06-01', NULL, '2025-10-20', 12), - (102, 2340.25, '2025-07-25', '2025-08-01', '2028-07-31', '2025-10-20', 14), - (103, 980.50, '2023-02-20', '2023-03-01', NULL, '2025-10-20', 17), - (104, 1560.00, '2023-04-15', '2023-05-01', NULL, '2025-10-20', 18), - (105, 1890.75, '2023-06-22', '2023-07-01', NULL, '2025-10-20', 20), - (106, 1200.00, '2023-08-10', '2023-09-01', NULL, '2025-10-20', 21), - (107, 1450.25, '2024-01-25', '2024-02-01', '2026-01-31', '2025-10-20', 24), - (108, 2100.50, '2024-03-20', '2024-04-01', NULL, '2025-10-20', 26), - (109, 780.00, '2024-05-12', '2024-06-01', NULL, '2025-10-20', 27), - (110, 1670.75, '2024-07-30', '2024-08-01', NULL, '2025-10-20', 29), - (111, 2340.00, '2025-01-15', '2025-02-01', '2027-01-31', '2025-10-20', 30), - (112, 890.25, '2025-03-22', '2025-04-01', NULL, '2025-10-20', 31), - (113, 1980.50, '2025-05-15', '2025-06-01', NULL, '2025-10-20', 33), - (114, 1340.00, '2025-07-20', '2025-08-01', NULL, '2025-10-20', 34), - (115, 1560.75, '2023-10-25', '2023-11-01', NULL, '2025-10-20', 36), - (116, 920.00, '2024-01-12', '2024-02-01', NULL, '2025-10-20', 37), - (117, 2230.25, '2024-03-18', '2024-04-01', NULL, '2025-10-20', 38), - (118, 1450.50, '2024-05-25', '2024-06-01', NULL, '2025-10-20', 39), - (119, 1890.00, '2024-07-20', '2024-08-01', '2027-07-31', '2025-10-20', 41), - (120, 780.75, '2025-01-10', '2025-02-01', NULL, '2025-10-20', 42), - (121, 2100.00, '2025-03-22', '2025-04-01', NULL, '2025-10-20', 43), - (122, 1340.25, '2025-05-15', '2025-06-01', NULL, '2025-10-20', 44), - (123, 1670.50, '2025-07-30', '2025-08-01', '2027-07-31', '2025-10-20', 45), - (124, 890.00, '2023-05-12', '2023-06-01', NULL, '2025-10-20', 46), - (125, 2340.75, '2023-07-25', '2023-08-01', NULL, '2025-10-20', 49), - (126, 980.00, '2024-01-20', '2024-02-01', NULL, '2025-10-20', 50), - (127, 1560.25, '2024-03-15', '2024-04-01', NULL, '2025-10-20', 1), - (128, 1890.50, '2024-05-22', '2024-06-01', NULL, '2025-10-20', 2), - (129, 1200.00, '2024-07-18', '2024-08-01', NULL, '2025-10-20', 6), - (130, 1450.75, '2025-01-12', '2025-02-01', '2027-01-31', '2025-10-20', 7), - (131, 2100.00, '2025-03-25', '2025-04-01', NULL, '2025-10-20', 9), - (132, 780.25, '2025-05-20', '2025-06-01', NULL, '2025-10-20', 10), - (133, 1670.50, '2023-08-15', '2023-09-01', NULL, '2025-10-20', 11), - (134, 2340.00, '2023-10-22', '2023-11-01', NULL, '2025-10-20', 12), - (135, 890.75, '2024-01-15', '2024-02-01', NULL, '2025-10-20', 14), - (136, 1980.25, '2024-03-30', '2024-04-01', NULL, '2025-10-20', 17), - (137, 1340.50, '2024-05-25', '2024-06-01', NULL, '2025-10-20', 18), - (138, 1560.00, '2025-01-18', '2025-02-01', '2027-01-31', '2025-10-20', 20), - (139, 920.75, '2025-03-12', '2025-04-01', NULL, '2025-10-20', 21), - (140, 2230.00, '2025-05-25', '2025-06-01', NULL, '2025-10-20', 24), - (141, 1450.25, '2023-06-20', '2023-07-01', NULL, '2025-10-20', 26), - (142, 1890.50, '2023-08-15', '2023-09-01', NULL, '2025-10-20', 27), - (143, 780.00, '2024-01-22', '2024-02-01', NULL, '2025-10-20', 29), - (144, 2100.75, '2024-03-18', '2024-04-01', NULL, '2025-10-20', 30), - (145, 1340.00, '2024-05-12', '2024-06-01', NULL, '2025-10-20', 31), - (146, 1670.25, '2025-01-25', '2025-02-01', '2027-01-31', '2025-10-20', 33), - (147, 890.50, '2025-03-20', '2025-04-01', NULL, '2025-10-20', 34), - (148, 2340.00, '2025-05-15', '2025-06-01', NULL, '2025-10-20', 36), - (149, 980.75, '2025-07-22', '2025-08-01', NULL, '2025-10-20', 37), - (150, 1560.00, '2023-09-25', '2023-10-01', NULL, '2025-10-20', 38), - (151, 1890.25, '2024-01-15', '2024-02-01', NULL, '2025-10-20', 39), - (152, 1200.50, '2024-03-22', '2024-04-01', NULL, '2025-10-20', 41), - (153, 1450.00, '2024-05-18', '2024-06-01', '2027-05-31', '2025-10-20', 42), - (154, 2100.75, '2025-01-12', '2025-02-01', NULL, '2025-10-20', 43), - (155, 780.00, '2025-03-25', '2025-04-01', NULL, '2025-10-20', 44), - (156, 1670.25, '2025-05-20', '2025-06-01', NULL, '2025-10-20', 45), - (157, 2340.50, '2023-07-12', '2023-08-01', NULL, '2025-10-20', 46), - (158, 890.00, '2024-01-25', '2024-02-01', NULL, '2025-10-20', 49), - (159, 1980.75, '2024-03-20', '2024-04-01', NULL, '2025-10-20', 50), - (160, 1340.00, '2024-05-15', '2024-06-01', NULL, '2025-10-20', 1), - (161, 1560.25, '2025-01-22', '2025-02-01', NULL, '2025-10-20', 2), - (162, 920.50, '2025-03-18', '2025-04-01', NULL, '2025-10-20', 6), - (163, 2230.00, '2025-05-12', '2025-06-01', NULL, '2025-10-20', 7), - (164, 1450.75, '2023-10-15', '2023-11-01', NULL, '2025-10-20', 9), - (165, 1890.00, '2024-01-20', '2024-02-01', NULL, '2025-10-20', 10), - (166, 780.25, '2024-03-25', '2024-04-01', NULL, '2025-10-20', 11), - (167, 2100.50, '2024-05-22', '2024-06-01', NULL, '2025-10-20', 12), - (168, 1340.00, '2025-01-15', '2025-02-01', NULL, '2025-10-20', 14), - (169, 1670.75, '2025-03-30', '2025-04-01', NULL, '2025-10-20', 17), - (170, 890.00, '2025-05-25', '2025-06-01', NULL, '2025-10-20', 18), - (171, 2340.25, '2023-12-12', '2024-01-01', NULL, '2025-10-20', 20), - (172, 980.50, '2024-02-20', '2024-03-01', NULL, '2025-10-20', 21), - (173, 1560.00, '2024-04-15', '2024-05-01', NULL, '2025-10-20', 24), - (174, 1890.75, '2024-06-22', '2024-07-01', NULL, '2025-10-20', 26), - (175, 1200.00, '2025-01-18', '2025-02-01', NULL, '2025-10-20', 27), - (34, 4500.00, '2023-02-15', '2023-03-01', NULL, '2025-10-20', 3), - (35, 7800.25, '2023-04-10', '2023-05-01', '2026-04-30', '2025-10-20', 4), - (36, 3200.50, '2023-06-25', '2023-07-01', NULL, '2025-10-20', 13), - (37, 8900.00, '2023-08-20', '2023-09-01', NULL, '2025-10-20', 16), - (38, 5600.75, '2023-10-15', '2023-11-01', NULL, '2025-10-20', 19), - (39, 4100.00, '2024-01-05', '2024-02-01', NULL, '2025-10-20', 22), - (40, 6700.25, '2024-03-12', '2024-04-01', '2027-03-31', '2025-10-20', 25), - (41, 2900.50, '2024-05-30', '2024-06-01', NULL, '2025-10-20', 32), - (42, 8500.00, '2024-07-25', '2024-08-01', NULL, '2025-10-20', 35), - (43, 3800.75, '2024-09-20', '2024-10-01', NULL, '2025-10-20', 40), - (44, 7200.00, '2025-01-15', '2025-02-01', NULL, '2025-10-20', 47), - (71, 5600.00, '2023-05-20', '2023-06-01', NULL, '2025-10-20', 3), - (72, 9200.25, '2023-07-15', '2023-08-01', '2027-07-31', '2025-10-20', 4), - (73, 3400.50, '2023-09-25', '2023-10-01', NULL, '2025-10-20', 13), - (74, 7800.00, '2024-01-20', '2024-02-01', NULL, '2025-10-20', 16), - (75, 4500.75, '2024-03-12', '2024-04-01', NULL, '2025-10-20', 19), - (76, 2900.00, '2024-05-30', '2024-06-01', NULL, '2025-10-20', 22), - (77, 6800.25, '2024-07-25', '2024-08-01', '2028-07-31', '2025-10-20', 25), - (78, 3100.50, '2025-01-15', '2025-02-01', NULL, '2025-10-20', 32), - (79, 9400.00, '2025-03-20', '2025-04-01', NULL, '2025-10-20', 35), - (80, 4200.75, '2025-05-12', '2025-06-01', NULL, '2025-10-20', 40), - (45, 980.00, '2023-05-01', '2023-06-01', '2024-12-31', '2024-12-31', 5), - (46, 2100.50, '2023-07-10', '2023-08-01', '2023-06-30', '2023-06-30', 8), - (47, 1450.25, '2024-02-15', '2024-03-01', '2025-01-15', '2025-01-15', 15), - (48, 890.75, '2023-03-20', '2023-04-01', '2023-09-01', '2023-09-01', 23), - (49, 1670.00, '2024-08-10', '2024-09-01', '2024-02-28', '2024-02-28', 28), - (50, 2340.50, '2025-03-05', '2025-04-01', '2025-05-31', '2025-05-31', 48); \ No newline at end of file +INSERT INTO contract (COST_AMOUNT, CREATED_AT, START_DATE, END_DATE, UPDATED_AT, CLIENT_ID) +VALUES + (1250.00, '2023-01-15', '2023-02-01', NULL, '2025-10-20', 1), + (890.50, '2023-03-10', '2023-04-01', NULL, '2025-10-20', 2), + (2100.00, '2023-05-05', '2023-06-01', NULL, '2025-10-20', 6), + (750.75, '2023-07-20', '2023-08-01', NULL, '2025-10-20', 7), + (1450.25, '2023-09-12', '2023-10-01', NULL, '2025-10-20', 9), + (980.00, '2023-11-08', '2023-12-01', NULL, '2025-10-20', 10), + (1675.50, '2024-01-25', '2024-02-01', NULL, '2025-10-20', 11), + (1120.00, '2024-03-18', '2024-04-01', '2026-03-31', '2025-10-20', 12), + (650.00, '2024-05-30', '2024-06-01', NULL, '2025-10-20', 14), + (1890.75, '2024-07-15', '2024-08-01', NULL, '2025-10-20', 17), + (920.25, '2024-09-22', '2024-10-01', NULL, '2025-10-20', 18), + (2340.00, '2024-11-10', '2024-12-01', '2026-11-30', '2025-10-20', 20), + (780.50, '2025-01-05', '2025-02-01', NULL, '2025-10-20', 21), + (1560.00, '2025-03-12', '2025-04-01', NULL, '2025-10-20', 24), + (890.00, '2025-05-20', '2025-06-01', NULL, '2025-10-20', 26), + (2100.25, '2025-07-08', '2025-08-01', '2027-07-31', '2025-10-20', 27), + (1345.75, '2025-09-15', '2025-10-01', NULL, '2025-10-20', 29), + (1670.00, '2023-02-28', '2023-03-01', NULL, '2025-10-20', 30), + (980.50, '2023-04-15', '2023-05-01', NULL, '2025-10-20', 31), + (2450.00, '2023-06-10', '2023-07-01', '2025-06-30', '2025-10-20', 33), + (720.25, '2023-08-25', '2023-09-01', NULL, '2025-10-20', 34), + (1890.75, '2023-10-20', '2023-11-01', NULL, '2025-10-20', 36), + (1125.00, '2024-01-12', '2024-02-01', NULL, '2025-10-20', 37), + (1560.50, '2024-03-05', '2024-04-01', '2026-03-31', '2025-10-20', 38), + (890.00, '2024-05-18', '2024-06-01', NULL, '2025-10-20', 39), + (2230.25, '2024-07-30', '2024-08-01', NULL, '2025-10-20', 41), + (1450.75, '2024-09-22', '2024-10-01', NULL, '2025-10-20', 42), + (1780.00, '2025-01-15', '2025-02-01', '2027-01-31', '2025-10-20', 43), + (920.50, '2025-03-10', '2025-04-01', NULL, '2025-10-20', 44), + (2010.00, '2025-05-05', '2025-06-01', NULL, '2025-10-20', 45), + (1340.25, '2025-07-20', '2025-08-01', NULL, '2025-10-20', 46), + (1675.50, '2025-09-12', '2025-10-01', '2027-09-30', '2025-10-20', 49), + (890.00, '2023-01-08', '2023-02-01', NULL, '2025-10-20', 50), + (1200.00, '2023-12-15', '2024-01-01', NULL, '2025-10-20', 1), + (950.25, '2024-02-20', '2024-03-01', NULL, '2025-10-20', 2), + (1780.50, '2024-04-12', '2024-05-01', NULL, '2025-10-20', 6), + (680.00, '2024-06-25', '2024-07-01', NULL, '2025-10-20', 7), + (1980.75, '2024-08-18', '2024-09-01', NULL, '2025-10-20', 9), + (1050.00, '2025-01-10', '2025-02-01', NULL, '2025-10-20', 10), + (2340.25, '2025-03-05', '2025-04-01', '2027-03-31', '2025-10-20', 11), + (1450.50, '2025-05-22', '2025-06-01', NULL, '2025-10-20', 12), + (890.00, '2023-06-15', '2023-07-01', NULL, '2025-10-20', 14), + (1670.75, '2023-08-20', '2023-09-01', NULL, '2025-10-20', 17), + (2100.00, '2023-10-12', '2023-11-01', NULL, '2025-10-20', 18), + (780.25, '2024-01-25', '2024-02-01', NULL, '2025-10-20', 20), + (1890.50, '2024-03-30', '2024-04-01', '2026-03-31', '2025-10-20', 21), + (1340.00, '2024-05-15', '2024-06-01', NULL, '2025-10-20', 24), + (1560.75, '2024-07-20', '2024-08-01', NULL, '2025-10-20', 26), + (920.00, '2025-01-12', '2025-02-01', NULL, '2025-10-20', 27), + (2230.25, '2025-03-18', '2025-04-01', NULL, '2025-10-20', 29), + (1450.50, '2025-05-10', '2025-06-01', NULL, '2025-10-20', 30), + (1780.00, '2025-07-25', '2025-08-01', '2027-07-31', '2025-10-20', 31), + (980.75, '2023-04-08', '2023-05-01', NULL, '2025-10-20', 33), + (1200.00, '2023-11-10', '2023-12-01', NULL, '2025-10-20', 34), + (1670.25, '2024-02-15', '2024-03-01', NULL, '2025-10-20', 36), + (890.50, '2024-04-20', '2024-05-01', NULL, '2025-10-20', 37), + (2340.00, '2024-06-12', '2024-07-01', '2027-06-30', '2025-10-20', 38), + (980.75, '2024-08-25', '2024-09-01', NULL, '2025-10-20', 39), + (1890.00, '2025-01-18', '2025-02-01', NULL, '2025-10-20', 41), + (1450.25, '2025-03-10', '2025-04-01', NULL, '2025-10-20', 42), + (2100.50, '2025-05-22', '2025-06-01', '2027-05-31', '2025-10-20', 43), + (780.00, '2025-07-15', '2025-08-01', NULL, '2025-10-20', 44), + (1560.75, '2025-09-20', '2025-10-01', NULL, '2025-10-20', 45), + (1340.00, '2023-03-12', '2023-04-01', NULL, '2025-10-20', 46), + (1780.25, '2023-05-25', '2023-06-01', NULL, '2025-10-20', 49), + (920.50, '2023-07-20', '2023-08-01', NULL, '2025-10-20', 50), + (2230.00, '2023-09-15', '2023-10-01', NULL, '2025-10-20', 1), + (1450.75, '2024-01-10', '2024-02-01', '2026-01-31', '2025-10-20', 2), + (1890.00, '2024-03-22', '2024-04-01', NULL, '2025-10-20', 6), + (780.25, '2024-05-15', '2024-06-01', NULL, '2025-10-20', 7), + (2100.50, '2024-07-30', '2024-08-01', NULL, '2025-10-20', 9), + (1340.00, '2025-01-12', '2025-02-01', NULL, '2025-10-20', 10), + (1670.75, '2025-03-18', '2025-04-01', NULL, '2025-10-20', 11), + (890.00, '2025-05-10', '2025-06-01', NULL, '2025-10-20', 12), + (2340.25, '2025-07-25', '2025-08-01', '2028-07-31', '2025-10-20', 14), + (980.50, '2023-02-20', '2023-03-01', NULL, '2025-10-20', 17), + (1560.00, '2023-04-15', '2023-05-01', NULL, '2025-10-20', 18), + (1890.75, '2023-06-22', '2023-07-01', NULL, '2025-10-20', 20), + (1200.00, '2023-08-10', '2023-09-01', NULL, '2025-10-20', 21), + (1450.25, '2024-01-25', '2024-02-01', '2026-01-31', '2025-10-20', 24), + (2100.50, '2024-03-20', '2024-04-01', NULL, '2025-10-20', 26), + (780.00, '2024-05-12', '2024-06-01', NULL, '2025-10-20', 27), + (1670.75, '2024-07-30', '2024-08-01', NULL, '2025-10-20', 29), + (2340.00, '2025-01-15', '2025-02-01', '2027-01-31', '2025-10-20', 30), + (890.25, '2025-03-22', '2025-04-01', NULL, '2025-10-20', 31), + (1980.50, '2025-05-15', '2025-06-01', NULL, '2025-10-20', 33), + (1340.00, '2025-07-20', '2025-08-01', NULL, '2025-10-20', 34), + (1560.75, '2023-10-25', '2023-11-01', NULL, '2025-10-20', 36), + (920.00, '2024-01-12', '2024-02-01', NULL, '2025-10-20', 37), + (2230.25, '2024-03-18', '2024-04-01', NULL, '2025-10-20', 38), + (1450.50, '2024-05-25', '2024-06-01', NULL, '2025-10-20', 39), + (1890.00, '2024-07-20', '2024-08-01', '2027-07-31', '2025-10-20', 41), + (780.75, '2025-01-10', '2025-02-01', NULL, '2025-10-20', 42), + (2100.00, '2025-03-22', '2025-04-01', NULL, '2025-10-20', 43), + (1340.25, '2025-05-15', '2025-06-01', NULL, '2025-10-20', 44), + (1670.50, '2025-07-30', '2025-08-01', '2027-07-31', '2025-10-20', 45), + (890.00, '2023-05-12', '2023-06-01', NULL, '2025-10-20', 46), + (2340.75, '2023-07-25', '2023-08-01', NULL, '2025-10-20', 49), + (980.00, '2024-01-20', '2024-02-01', NULL, '2025-10-20', 50), + (1560.25, '2024-03-15', '2024-04-01', NULL, '2025-10-20', 1), + (1890.50, '2024-05-22', '2024-06-01', NULL, '2025-10-20', 2), + (1200.00, '2024-07-18', '2024-08-01', NULL, '2025-10-20', 6), + (1450.75, '2025-01-12', '2025-02-01', '2027-01-31', '2025-10-20', 7), + (2100.00, '2025-03-25', '2025-04-01', NULL, '2025-10-20', 9), + (780.25, '2025-05-20', '2025-06-01', NULL, '2025-10-20', 10), + (1670.50, '2023-08-15', '2023-09-01', NULL, '2025-10-20', 11), + (2340.00, '2023-10-22', '2023-11-01', NULL, '2025-10-20', 12), + (890.75, '2024-01-15', '2024-02-01', NULL, '2025-10-20', 14), + (1980.25, '2024-03-30', '2024-04-01', NULL, '2025-10-20', 17), + (1340.50, '2024-05-25', '2024-06-01', NULL, '2025-10-20', 18), + (1560.00, '2025-01-18', '2025-02-01', '2027-01-31', '2025-10-20', 20), + (920.75, '2025-03-12', '2025-04-01', NULL, '2025-10-20', 21), + (2230.00, '2025-05-25', '2025-06-01', NULL, '2025-10-20', 24), + (1450.25, '2023-06-20', '2023-07-01', NULL, '2025-10-20', 26), + (1890.50, '2023-08-15', '2023-09-01', NULL, '2025-10-20', 27), + (780.00, '2024-01-22', '2024-02-01', NULL, '2025-10-20', 29), + (2100.75, '2024-03-18', '2024-04-01', NULL, '2025-10-20', 30), + (1340.00, '2024-05-12', '2024-06-01', NULL, '2025-10-20', 31), + (1670.25, '2025-01-25', '2025-02-01', '2027-01-31', '2025-10-20', 33), + (890.50, '2025-03-20', '2025-04-01', NULL, '2025-10-20', 34), + (2340.00, '2025-05-15', '2025-06-01', NULL, '2025-10-20', 36), + (980.75, '2025-07-22', '2025-08-01', NULL, '2025-10-20', 37), + (1560.00, '2023-09-25', '2023-10-01', NULL, '2025-10-20', 38), + (1890.25, '2024-01-15', '2024-02-01', NULL, '2025-10-20', 39), + (1200.50, '2024-03-22', '2024-04-01', NULL, '2025-10-20', 41), + (1450.00, '2024-05-18', '2024-06-01', '2027-05-31', '2025-10-20', 42), + (2100.75, '2025-01-12', '2025-02-01', NULL, '2025-10-20', 43), + (780.00, '2025-03-25', '2025-04-01', NULL, '2025-10-20', 44), + (1670.25, '2025-05-20', '2025-06-01', NULL, '2025-10-20', 45), + (2340.50, '2023-07-12', '2023-08-01', NULL, '2025-10-20', 46), + (890.00, '2024-01-25', '2024-02-01', NULL, '2025-10-20', 49), + (1980.75, '2024-03-20', '2024-04-01', NULL, '2025-10-20', 50), + (1340.00, '2024-05-15', '2024-06-01', NULL, '2025-10-20', 1), + (1560.25, '2025-01-22', '2025-02-01', NULL, '2025-10-20', 2), + (920.50, '2025-03-18', '2025-04-01', NULL, '2025-10-20', 6), + (2230.00, '2025-05-12', '2025-06-01', NULL, '2025-10-20', 7), + (1450.75, '2023-10-15', '2023-11-01', NULL, '2025-10-20', 9), + (1890.00, '2024-01-20', '2024-02-01', NULL, '2025-10-20', 10), + (780.25, '2024-03-25', '2024-04-01', NULL, '2025-10-20', 11), + (2100.50, '2024-05-22', '2024-06-01', NULL, '2025-10-20', 12), + (1340.00, '2025-01-15', '2025-02-01', NULL, '2025-10-20', 14), + (1670.75, '2025-03-30', '2025-04-01', NULL, '2025-10-20', 17), + (890.00, '2025-05-25', '2025-06-01', NULL, '2025-10-20', 18), + (2340.25, '2023-12-12', '2024-01-01', NULL, '2025-10-20', 20), + (980.50, '2024-02-20', '2024-03-01', NULL, '2025-10-20', 21), + (1560.00, '2024-04-15', '2024-05-01', NULL, '2025-10-20', 24), + (1890.75, '2024-06-22', '2024-07-01', NULL, '2025-10-20', 26), + (1200.00, '2025-01-18', '2025-02-01', NULL, '2025-10-20', 27), + (4500.00, '2023-02-15', '2023-03-01', NULL, '2025-10-20', 3), + (7800.25, '2023-04-10', '2023-05-01', '2026-04-30', '2025-10-20', 4), + (3200.50, '2023-06-25', '2023-07-01', NULL, '2025-10-20', 13), + (8900.00, '2023-08-20', '2023-09-01', NULL, '2025-10-20', 16), + (5600.75, '2023-10-15', '2023-11-01', NULL, '2025-10-20', 19), + (4100.00, '2024-01-05', '2024-02-01', NULL, '2025-10-20', 22), + (6700.25, '2024-03-12', '2024-04-01', '2027-03-31', '2025-10-20', 25), + (2900.50, '2024-05-30', '2024-06-01', NULL, '2025-10-20', 32), + (8500.00, '2024-07-25', '2024-08-01', NULL, '2025-10-20', 35), + (3800.75, '2024-09-20', '2024-10-01', NULL, '2025-10-20', 40), + (7200.00, '2025-01-15', '2025-02-01', NULL, '2025-10-20', 47), + (5600.00, '2023-05-20', '2023-06-01', NULL, '2025-10-20', 3), + (9200.25, '2023-07-15', '2023-08-01', '2027-07-31', '2025-10-20', 4), + (3400.50, '2023-09-25', '2023-10-01', NULL, '2025-10-20', 13), + (7800.00, '2024-01-20', '2024-02-01', NULL, '2025-10-20', 16), + (4500.75, '2024-03-12', '2024-04-01', NULL, '2025-10-20', 19), + (2900.00, '2024-05-30', '2024-06-01', NULL, '2025-10-20', 22), + (6800.25, '2024-07-25', '2024-08-01', '2028-07-31', '2025-10-20', 25), + (3100.50, '2025-01-15', '2025-02-01', NULL, '2025-10-20', 32), + (9400.00, '2025-03-20', '2025-04-01', NULL, '2025-10-20', 35), + (4200.75, '2025-05-12', '2025-06-01', NULL, '2025-10-20', 40), + (980.00, '2023-05-01', '2023-06-01', '2024-12-31', '2024-12-31', 5), + (2100.50, '2023-07-10', '2023-08-01', '2023-06-30', '2023-06-30', 8), + (1450.25, '2024-02-15', '2024-03-01', '2025-01-15', '2025-01-15', 15), + (890.75, '2023-03-20', '2023-04-01', '2023-09-01', '2023-09-01', 23), + (1670.00, '2024-08-10', '2024-09-01', '2024-02-28', '2024-02-28', 28), + (2340.50, '2025-03-05', '2025-04-01', '2025-05-31', '2025-05-31', 48); \ No newline at end of file From 06822ef86c36b6da4a261cbfd00bb5a23fc9b5e0 Mon Sep 17 00:00:00 2001 From: julien gourmet Date: Tue, 21 Oct 2025 19:26:59 +0200 Subject: [PATCH 4/6] fix(exception handling): add a globalException handler to refactoring code and manage in a more efficient way error. --- .../controller/ClientController.java | 90 +++---------- .../controller/ContractController.java | 26 +--- .../exception/GlobalExceptionHandler.java | 123 ++++++++++++++++++ .../gourmet/apifactory/model/Client.java | 3 +- .../apifactory/service/ClientService.java | 14 +- 5 files changed, 157 insertions(+), 99 deletions(-) create mode 100644 src/main/java/julien/gourmet/apifactory/exception/GlobalExceptionHandler.java diff --git a/src/main/java/julien/gourmet/apifactory/controller/ClientController.java b/src/main/java/julien/gourmet/apifactory/controller/ClientController.java index ff0d94d..6e88cdf 100644 --- a/src/main/java/julien/gourmet/apifactory/controller/ClientController.java +++ b/src/main/java/julien/gourmet/apifactory/controller/ClientController.java @@ -26,34 +26,19 @@ public class ClientController { @PostMapping("/person") public ResponseEntity createPerson(@RequestBody @Valid PersonCreateDTO dto) { - try { - Client created = clientService.savePerson(dto); - return ResponseEntity.status(HttpStatus.CREATED).body(created); - } catch (IllegalArgumentException ex) { - return ResponseEntity.status(HttpStatus.CONFLICT).body(null); - } catch (RuntimeException ex) { - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null); - } + Client created = clientService.savePerson(dto); + return ResponseEntity.status(HttpStatus.CREATED).body(created); } @PostMapping("/company") public ResponseEntity createCompany(@RequestBody @Valid CompanyCreateDTO dto) { - try { - Client created = clientService.saveCompany(dto); - return ResponseEntity.status(HttpStatus.CREATED).body(created); - } catch (IllegalArgumentException ex) { - return ResponseEntity.status(HttpStatus.CONFLICT).body(null); - } catch (RuntimeException ex) { - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null); - } + Client created = clientService.saveCompany(dto); + return ResponseEntity.status(HttpStatus.CREATED).body(created); } @GetMapping("/{id}") public ResponseEntity getClient(@PathVariable Long id) { Client client = clientService.getClientById(id); - if (client == null) { - return ResponseEntity.notFound().build(); - } return ResponseEntity.ok(client); } @@ -66,77 +51,38 @@ public ResponseEntity> getAllClients() { @PutMapping("/person/{clientId}") public ResponseEntity updatePerson(@PathVariable Long clientId, @RequestBody @Valid PersonUpdateDTO dto) { - try { - Client updated = clientService.updatePerson(clientId, dto); - return ResponseEntity.ok(updated); - } catch (IllegalArgumentException ex) { - return ResponseEntity.status(HttpStatus.CONFLICT).body(null); - } catch (RuntimeException ex) { - if (ex.getMessage().contains("not found")) { - return ResponseEntity.notFound().build(); - } - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null); - } + Client updated = clientService.updatePerson(clientId, dto); + return ResponseEntity.ok(updated); } @PutMapping("/company/{clientId}") public ResponseEntity updateCompany(@PathVariable Long clientId, @RequestBody @Valid CompanyUpdateDTO dto) { - try { - Client updated = clientService.updateCompany(clientId, dto); - return ResponseEntity.ok(updated); - } catch (IllegalArgumentException ex) { - return ResponseEntity.status(HttpStatus.CONFLICT).body(null); - } catch (RuntimeException ex) { - if (ex.getMessage().contains("not found")) { - return ResponseEntity.notFound().build(); - } - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null); - } + Client updated = clientService.updateCompany(clientId, dto); + return ResponseEntity.ok(updated); } @DeleteMapping("/{clientId}") public ResponseEntity deleteClient(@PathVariable Long clientId) { - try { - clientService.deleteClient(clientId); - return ResponseEntity.noContent().build(); - } catch (RuntimeException ex) { - if (ex.getMessage().contains("not found")) { - return ResponseEntity.notFound().build(); - } - throw ex; - } + clientService.deleteClient(clientId); + return ResponseEntity.noContent().build(); } @GetMapping("/{clientId}/contracts") public ResponseEntity> getClientContracts(@PathVariable Long clientId, @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime updatedAfter) { - try { - List contracts; - if (updatedAfter != null) { - contracts = contractService.getActiveContractByClientAndUpdatedAfter(clientId, updatedAfter); - } else { - contracts = contractService.getActiveContractByClient(clientId); - } - return ResponseEntity.ok(contracts); - } catch (RuntimeException ex) { - if (ex.getMessage().contains("not found")) { - return ResponseEntity.notFound().build(); - } - throw ex; + List contracts; + if (updatedAfter != null) { + contracts = contractService.getActiveContractByClientAndUpdatedAfter(clientId, updatedAfter); + } else { + contracts = contractService.getActiveContractByClient(clientId); } + return ResponseEntity.ok(contracts); } @GetMapping("/{clientId}/contracts/sum") public ResponseEntity getClientContractsSum(@PathVariable Long clientId) { - try { - BigDecimal sum = contractService.getActiveContractsSumByClientId(clientId); - return ResponseEntity.ok(sum); - } catch (RuntimeException ex) { - if (ex.getMessage().contains("not found")) { - return ResponseEntity.notFound().build(); - } - throw ex; - } + BigDecimal sum = contractService.getActiveContractsSumByClientId(clientId); + return ResponseEntity.ok(sum); } } diff --git a/src/main/java/julien/gourmet/apifactory/controller/ContractController.java b/src/main/java/julien/gourmet/apifactory/controller/ContractController.java index 52a105a..606e758 100644 --- a/src/main/java/julien/gourmet/apifactory/controller/ContractController.java +++ b/src/main/java/julien/gourmet/apifactory/controller/ContractController.java @@ -20,31 +20,13 @@ public class ContractController { @PostMapping public ResponseEntity createContract(@Valid @RequestBody ContractCreateDTO dto) { - try { - ContractResponseDTO created = contractService.createContract(dto); - return ResponseEntity.status(HttpStatus.CREATED).body(created); - } catch (IllegalArgumentException ex) { - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null); - } catch (RuntimeException ex) { - if (ex.getMessage().contains("not found")) { - return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null); - } - throw ex; - } + ContractResponseDTO created = contractService.createContract(dto); + return ResponseEntity.status(HttpStatus.CREATED).body(created); } @PutMapping("/{contractId}/cost") public ResponseEntity updateContractCost(@PathVariable Long contractId, @Valid @RequestBody ContractUpdateDTO dto) { - try { - ContractResponseDTO updated = contractService.updateContractCost(contractId, dto); - return ResponseEntity.ok(updated); - } catch (IllegalArgumentException ex) { - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null); - } catch (RuntimeException ex) { - if (ex.getMessage().contains("not found")) { - return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null); - } - throw ex; - } + ContractResponseDTO updated = contractService.updateContractCost(contractId, dto); + return ResponseEntity.ok(updated); } } diff --git a/src/main/java/julien/gourmet/apifactory/exception/GlobalExceptionHandler.java b/src/main/java/julien/gourmet/apifactory/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..8f1e1fb --- /dev/null +++ b/src/main/java/julien/gourmet/apifactory/exception/GlobalExceptionHandler.java @@ -0,0 +1,123 @@ +package julien.gourmet.apifactory.exception; + +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +@RestControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity> handleValidationExceptions(MethodArgumentNotValidException ex) { + Map response = new HashMap<>(); + Map errors = new HashMap<>(); + + ex.getBindingResult().getFieldErrors().forEach(error -> { + String fieldName = error.getField(); + String errorMessage = error.getDefaultMessage(); + errors.put(fieldName, errorMessage); + }); + + response.put("timestamp", LocalDateTime.now()); + response.put("status", HttpStatus.BAD_REQUEST.value()); + response.put("error", "Validation Failed"); + response.put("message", "Invalid input data"); + response.put("validationErrors", errors); + + return ResponseEntity.badRequest().body(response); + } + + @ExceptionHandler(IllegalArgumentException.class) + public ResponseEntity> handleIllegalArgumentException(IllegalArgumentException ex) { + Map response = new HashMap<>(); + + // Determine the appropriate HTTP status based on the error message + HttpStatus status = HttpStatus.BAD_REQUEST; + String errorType = "Validation Error"; + + if (ex.getMessage().contains("already in use")) { + status = HttpStatus.CONFLICT; + errorType = "Conflict"; + } else if (ex.getMessage().contains("must be") || ex.getMessage().contains("required")) { + status = HttpStatus.BAD_REQUEST; + errorType = "Validation Error"; + } + + response.put("timestamp", LocalDateTime.now()); + response.put("status", status.value()); + response.put("error", errorType); + response.put("message", ex.getMessage()); + + return ResponseEntity.status(status).body(response); + } + + @ExceptionHandler(DataIntegrityViolationException.class) + public ResponseEntity> handleDataIntegrityViolationException(DataIntegrityViolationException ex) { + Map response = new HashMap<>(); + + String message = ex.getMessage(); + String userMessage = "Data integrity violation"; + + // Check if this is actually a "not found" error disguised as a constraint violation + // This can happen when Hibernate tries to update a non-existent entity + if (message.contains("where id=?") || message.contains("update client set")) { + // This looks like an update on a non-existent entity + response.put("error", "Client not found"); + response.put("message", "Client not found"); + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response); + } + + if (message.contains("EMAIL") || message.contains("email")) { + userMessage = "Email already in use"; + } else if (message.contains("PHONE") || message.contains("phone")) { + userMessage = "Phone number already in use"; + } else if (message.contains("IDENTIFIER") || message.contains("identifier")) { + userMessage = "Company identifier already in use"; + } + + response.put("timestamp", LocalDateTime.now()); + response.put("status", HttpStatus.CONFLICT.value()); + response.put("error", "Conflict"); + response.put("message", userMessage); + + return ResponseEntity.status(HttpStatus.CONFLICT).body(response); + } + + @ExceptionHandler(RuntimeException.class) + public ResponseEntity> handleRuntimeException(RuntimeException ex) { + Map response = new HashMap<>(); + + if (ex.getMessage().contains("not found")) { + response.put("error", "Client not found"); + response.put("message", ex.getMessage()); + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response); + } + + // Handle other runtime exceptions as internal server errors + response.put("timestamp", LocalDateTime.now()); + response.put("status", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("error", "Internal Server Error"); + response.put("message", ex.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + + // Handle specific validation errors for better error messages + @ExceptionHandler(Exception.class) + public ResponseEntity> handleGenericException(Exception ex) { + Map response = new HashMap<>(); + + response.put("timestamp", LocalDateTime.now()); + response.put("status", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("error", "Internal Server Error"); + response.put("message", "An unexpected error occurred"); + + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } +} diff --git a/src/main/java/julien/gourmet/apifactory/model/Client.java b/src/main/java/julien/gourmet/apifactory/model/Client.java index 84ec882..3440730 100644 --- a/src/main/java/julien/gourmet/apifactory/model/Client.java +++ b/src/main/java/julien/gourmet/apifactory/model/Client.java @@ -1,5 +1,6 @@ package julien.gourmet.apifactory.model; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; import jakarta.persistence.*; @@ -24,7 +25,6 @@ public abstract class Client { @Id @GeneratedValue(strategy = jakarta.persistence.GenerationType.IDENTITY) - private Long id; @NotBlank @@ -86,6 +86,7 @@ public void setStatus(ClientStatus status) { this.status = status; } + @JsonIgnore public LocalDateTime getDeletedAt() { return deletedAt; } diff --git a/src/main/java/julien/gourmet/apifactory/service/ClientService.java b/src/main/java/julien/gourmet/apifactory/service/ClientService.java index 0a21b9e..c274412 100644 --- a/src/main/java/julien/gourmet/apifactory/service/ClientService.java +++ b/src/main/java/julien/gourmet/apifactory/service/ClientService.java @@ -68,7 +68,10 @@ public List getAllClients() { } public Client updatePerson(Long id, PersonUpdateDTO dto) { - // Check if email is used by another active client (excluding current client) + // First check if client exists + Person person = (Person) getClientById(id); + + // Then check if email is used by another active client (excluding current client) if (clientRepository.existsActiveByEmailAndIdNot(dto.getEmail(), id)) { throw new IllegalArgumentException("Email already in use"); } @@ -76,7 +79,7 @@ public Client updatePerson(Long id, PersonUpdateDTO dto) { if (clientRepository.existsActiveByPhoneAndIdNot(dto.getPhone(), id)) { throw new IllegalArgumentException("Phone already in use"); } - Person person = (Person) getClientById(id); + person.setName(dto.getName()); person.setEmail(dto.getEmail()); person.setPhone(dto.getPhone()); @@ -84,7 +87,10 @@ public Client updatePerson(Long id, PersonUpdateDTO dto) { } public Client updateCompany(Long id, CompanyUpdateDTO dto) { - // Check if email is used by another active client (excluding current client) + // First check if client exists + Company company = (Company) getClientById(id); + + // Then check if email is used by another active client (excluding current client) if (clientRepository.existsActiveByEmailAndIdNot(dto.getEmail(), id)) { throw new IllegalArgumentException("Email already in use"); } @@ -92,7 +98,7 @@ public Client updateCompany(Long id, CompanyUpdateDTO dto) { if (clientRepository.existsActiveByPhoneAndIdNot(dto.getPhone(), id)) { throw new IllegalArgumentException("Phone already in use"); } - Company company = (Company) getClientById(id); + company.setName(dto.getName()); company.setEmail(dto.getEmail()); company.setPhone(dto.getPhone()); From ebaa3d758344cd49a5167f70318842e361be9e33 Mon Sep 17 00:00:00 2001 From: julien gourmet Date: Tue, 21 Oct 2025 19:31:09 +0200 Subject: [PATCH 5/6] fix(test): refactoring the tests to be compliant with the new error handling --- .../controller/ClientControllerTest.java | 14 ++++++------- .../controller/ContractControllerTest.java | 6 +++--- .../apifactory/service/ClientServiceTest.java | 20 +++++++++++++++---- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/test/java/julien/gourmet/apifactory/controller/ClientControllerTest.java b/src/test/java/julien/gourmet/apifactory/controller/ClientControllerTest.java index aa8045e..279df59 100644 --- a/src/test/java/julien/gourmet/apifactory/controller/ClientControllerTest.java +++ b/src/test/java/julien/gourmet/apifactory/controller/ClientControllerTest.java @@ -274,7 +274,7 @@ void testGetClientById_Success() throws Exception { @Test void testGetClientById_NotFound() throws Exception { - when(clientService.getClientById(999L)).thenReturn(null); + when(clientService.getClientById(999L)).thenThrow(new RuntimeException("Client not found with id 999")); mockMvc.perform(get("/api/clients/999")) .andExpect(status().isNotFound()); @@ -700,7 +700,7 @@ void testCreateCompany_LongIdentifier_ShouldFail() throws Exception { @Test void testGetClientById_InvalidId_ShouldFail() throws Exception { mockMvc.perform(get("/api/clients/invalid")) - .andExpect(status().isBadRequest()); + .andExpect(status().isInternalServerError()); verify(clientService, never()).getClientById(any()); } @@ -715,7 +715,7 @@ void testUpdatePerson_InvalidId_ShouldFail() throws Exception { mockMvc.perform(put("/api/clients/person/invalid") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(dto))) - .andExpect(status().isBadRequest()); + .andExpect(status().isInternalServerError()); verify(clientService, never()).updatePerson(any(), any()); } @@ -730,7 +730,7 @@ void testUpdateCompany_InvalidId_ShouldFail() throws Exception { mockMvc.perform(put("/api/clients/company/invalid") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(dto))) - .andExpect(status().isBadRequest()); + .andExpect(status().isInternalServerError()); verify(clientService, never()).updateCompany(any(), any()); } @@ -738,7 +738,7 @@ void testUpdateCompany_InvalidId_ShouldFail() throws Exception { @Test void testDeleteClient_InvalidId_ShouldFail() throws Exception { mockMvc.perform(delete("/api/clients/invalid")) - .andExpect(status().isBadRequest()); + .andExpect(status().isInternalServerError()); verify(clientService, never()).deleteClient(any()); } @@ -746,7 +746,7 @@ void testDeleteClient_InvalidId_ShouldFail() throws Exception { @Test void testGetClientContracts_InvalidId_ShouldFail() throws Exception { mockMvc.perform(get("/api/clients/invalid/contracts")) - .andExpect(status().isBadRequest()); + .andExpect(status().isInternalServerError()); verify(contractService, never()).getActiveContractByClient(any()); } @@ -754,7 +754,7 @@ void testGetClientContracts_InvalidId_ShouldFail() throws Exception { @Test void testGetClientContractsSum_InvalidId_ShouldFail() throws Exception { mockMvc.perform(get("/api/clients/invalid/contracts/sum")) - .andExpect(status().isBadRequest()); + .andExpect(status().isInternalServerError()); verify(contractService, never()).getActiveContractsSumByClientId(any()); } diff --git a/src/test/java/julien/gourmet/apifactory/controller/ContractControllerTest.java b/src/test/java/julien/gourmet/apifactory/controller/ContractControllerTest.java index ec52566..2c78809 100644 --- a/src/test/java/julien/gourmet/apifactory/controller/ContractControllerTest.java +++ b/src/test/java/julien/gourmet/apifactory/controller/ContractControllerTest.java @@ -308,7 +308,7 @@ void testUpdateContractCost_InvalidContractId_ShouldFail() throws Exception { mockMvc.perform(put("/api/contracts/invalid/cost") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(dto))) - .andExpect(status().isBadRequest()); + .andExpect(status().isInternalServerError()); verify(contractService, never()).updateContractCost(any(), any()); } @@ -359,7 +359,7 @@ void testCreateContract_InvalidJson_ShouldFail() throws Exception { mockMvc.perform(post("/api/contracts") .contentType(MediaType.APPLICATION_JSON) .content("invalid json")) - .andExpect(status().isBadRequest()); + .andExpect(status().isInternalServerError()); verify(contractService, never()).createContract(any()); } @@ -369,7 +369,7 @@ void testUpdateContractCost_InvalidJson_ShouldFail() throws Exception { mockMvc.perform(put("/api/contracts/1/cost") .contentType(MediaType.APPLICATION_JSON) .content("invalid json")) - .andExpect(status().isBadRequest()); + .andExpect(status().isInternalServerError()); verify(contractService, never()).updateContractCost(any(), any()); } diff --git a/src/test/java/julien/gourmet/apifactory/service/ClientServiceTest.java b/src/test/java/julien/gourmet/apifactory/service/ClientServiceTest.java index 060969c..585d939 100644 --- a/src/test/java/julien/gourmet/apifactory/service/ClientServiceTest.java +++ b/src/test/java/julien/gourmet/apifactory/service/ClientServiceTest.java @@ -256,6 +256,9 @@ void testUpdatePerson_Success() { @Test void testUpdatePerson_DuplicateEmail_ShouldThrowException() { + Person person = new Person(); + person.setId(1L); + when(clientRepository.findActiveById(1L)).thenReturn(Optional.of(person)); when(clientRepository.existsActiveByEmailAndIdNot(personUpdateDTO.getEmail(), 1L)).thenReturn(true); IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { @@ -263,13 +266,16 @@ void testUpdatePerson_DuplicateEmail_ShouldThrowException() { }); assertEquals("Email already in use", exception.getMessage()); + verify(clientRepository).findActiveById(1L); verify(clientRepository).existsActiveByEmailAndIdNot(personUpdateDTO.getEmail(), 1L); - verify(clientRepository, never()).findActiveById(any()); verify(clientRepository, never()).save(any()); } @Test void testUpdatePerson_DuplicatePhone_ShouldThrowException() { + Person person = new Person(); + person.setId(1L); + when(clientRepository.findActiveById(1L)).thenReturn(Optional.of(person)); when(clientRepository.existsActiveByEmailAndIdNot(personUpdateDTO.getEmail(), 1L)).thenReturn(false); when(clientRepository.existsActiveByPhoneAndIdNot(personUpdateDTO.getPhone(), 1L)).thenReturn(true); @@ -278,9 +284,9 @@ void testUpdatePerson_DuplicatePhone_ShouldThrowException() { }); assertEquals("Phone already in use", exception.getMessage()); + verify(clientRepository).findActiveById(1L); verify(clientRepository).existsActiveByEmailAndIdNot(personUpdateDTO.getEmail(), 1L); verify(clientRepository).existsActiveByPhoneAndIdNot(personUpdateDTO.getPhone(), 1L); - verify(clientRepository, never()).findActiveById(any()); verify(clientRepository, never()).save(any()); } @@ -304,6 +310,9 @@ void testUpdateCompany_Success() { @Test void testUpdateCompany_DuplicateEmail_ShouldThrowException() { + Company company = new Company(); + company.setId(2L); + when(clientRepository.findActiveById(2L)).thenReturn(Optional.of(company)); when(clientRepository.existsActiveByEmailAndIdNot(companyUpdateDTO.getEmail(), 2L)).thenReturn(true); IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { @@ -311,13 +320,16 @@ void testUpdateCompany_DuplicateEmail_ShouldThrowException() { }); assertEquals("Email already in use", exception.getMessage()); + verify(clientRepository).findActiveById(2L); verify(clientRepository).existsActiveByEmailAndIdNot(companyUpdateDTO.getEmail(), 2L); - verify(clientRepository, never()).findActiveById(any()); verify(clientRepository, never()).save(any()); } @Test void testUpdateCompany_DuplicatePhone_ShouldThrowException() { + Company company = new Company(); + company.setId(2L); + when(clientRepository.findActiveById(2L)).thenReturn(Optional.of(company)); when(clientRepository.existsActiveByEmailAndIdNot(companyUpdateDTO.getEmail(), 2L)).thenReturn(false); when(clientRepository.existsActiveByPhoneAndIdNot(companyUpdateDTO.getPhone(), 2L)).thenReturn(true); @@ -326,9 +338,9 @@ void testUpdateCompany_DuplicatePhone_ShouldThrowException() { }); assertEquals("Phone already in use", exception.getMessage()); + verify(clientRepository).findActiveById(2L); verify(clientRepository).existsActiveByEmailAndIdNot(companyUpdateDTO.getEmail(), 2L); verify(clientRepository).existsActiveByPhoneAndIdNot(companyUpdateDTO.getPhone(), 2L); - verify(clientRepository, never()).findActiveById(any()); verify(clientRepository, never()).save(any()); } From 0af0e257e16a415d7e9ed1309458e5a3e3ea9265 Mon Sep 17 00:00:00 2001 From: julien gourmet Date: Tue, 21 Oct 2025 19:32:22 +0200 Subject: [PATCH 6/6] feat (postman): add Postman collection for API testing --- postman/API Factory.postman_collection.json | 328 ++++++++++++++++++++ 1 file changed, 328 insertions(+) create mode 100644 postman/API Factory.postman_collection.json diff --git a/postman/API Factory.postman_collection.json b/postman/API Factory.postman_collection.json new file mode 100644 index 0000000..c50f5a7 --- /dev/null +++ b/postman/API Factory.postman_collection.json @@ -0,0 +1,328 @@ +{ + "info": { + "_postman_id": "f29da718-adc9-4c4b-b45a-8065d2602e07", + "name": "API Factory", + "description": "Insurance Management API", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "31283114", + "_collection_link": "https://letsprintswiss.postman.co/workspace/LetsPrintSwiss-Workspace~a8d98193-e8c7-4b0e-bd49-ac89d7873836/collection/31283114-f29da718-adc9-4c4b-b45a-8065d2602e07?action=share&source=collection_link&creator=31283114" + }, + "item": [ + { + "name": "Clients", + "item": [ + { + "name": "Create Person", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"Jean Dupont\",\n \"phone\": \"+41781234567\",\n \"email\": \"jean.dupont@example.com\",\n \"birthDate\": \"1985-03-15\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/api/clients/person", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "clients", + "person" + ] + } + }, + "response": [] + }, + { + "name": "Create Company", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"Tech Solutions SA\",\n \"phone\": \"+41787654321\",\n \"email\": \"contact@techsolutions.ch\",\n \"identifier\": \"TEC-123\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/api/clients/company", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "clients", + "company" + ] + } + }, + "response": [] + }, + { + "name": "Get All Clients", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/api/clients", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "clients" + ] + } + }, + "response": [] + }, + { + "name": "Get Client by ID", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/api/clients/1", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "clients", + "1" + ] + } + }, + "response": [] + }, + { + "name": "Update Person", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"Jean Dupont Updated\",\n \"phone\": \"+41781234568\",\n \"email\": \"jean.dupont.updated@example.com\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/api/clients/person/1", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "clients", + "person", + "1" + ] + } + }, + "response": [] + }, + { + "name": "Update Company", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"Tech Solutions SA Updated\",\n \"phone\": \"+41787654322\",\n \"email\": \"contact.updated@techsolutions.ch\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/api/clients/company/2", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "clients", + "company", + "2" + ] + } + }, + "response": [] + }, + { + "name": "Delete Client", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{baseUrl}}/api/clients/1", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "clients", + "1" + ] + } + }, + "response": [] + }, + { + "name": "Get Client Contracts", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/api/clients/1/contracts", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "clients", + "1", + "contracts" + ] + } + }, + "response": [] + }, + { + "name": "Get Client Contracts (Filtered by Date)", + "request": { + "method": "GET", + "header": [ + { + "key": "", + "value": "", + "type": "text", + "disabled": true + } + ], + "url": { + "raw": "{{baseUrl}}/api/clients/2/contracts?updatedAfter=2025-10-21T00:00:00", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "clients", + "2", + "contracts" + ], + "query": [ + { + "key": "updatedAfter", + "value": "2025-10-21T00:00:00" + } + ] + } + }, + "response": [] + }, + { + "name": "Get Client Contracts Sum", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/api/clients/1/contracts/sum", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "clients", + "1", + "contracts", + "sum" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Contracts", + "item": [ + { + "name": "Create Contract", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"clientId\": 1,\n \"startDate\": \"2024-01-01T00:00:00\",\n \"endDate\": \"2024-12-31T23:59:59\",\n \"costAmount\": 1200.00\n}" + }, + "url": { + "raw": "{{baseUrl}}/api/contracts", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "contracts" + ] + } + }, + "response": [] + }, + { + "name": "Update Contract Cost", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"costAmount\": 1500.00\n}" + }, + "url": { + "raw": "{{baseUrl}}/api/contracts/1/cost", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "api", + "contracts", + "1", + "cost" + ] + } + }, + "response": [] + } + ] + } + ], + "variable": [ + { + "key": "baseUrl", + "value": "http://localhost:8080" + } + ] +} \ No newline at end of file