From 24c14eec7d839757b9bda537e2c5e753d7fe7237 Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Sat, 7 Mar 2026 13:20:11 -0700 Subject: [PATCH 01/19] Add API infrastructure and DTOs --- connectionpetstore.properties | 3 +- pom.xml | 21 +++ src/main/java/module-info.java | 20 +++ .../example/petshopdesktop/api/ApiClient.java | 164 ++++++++++++++++++ .../example/petshopdesktop/api/ApiConfig.java | 34 ++++ .../api/dto/adoption/AdoptionRequest.java | 42 +++++ .../api/dto/adoption/AdoptionResponse.java | 51 ++++++ .../api/dto/analytics/DailySales.java | 25 +++ .../api/dto/analytics/DashboardResponse.java | 61 +++++++ .../api/dto/analytics/TopProduct.java | 33 ++++ .../dto/appointment/AppointmentRequest.java | 62 +++++++ .../dto/appointment/AppointmentResponse.java | 70 ++++++++ .../api/dto/auth/LoginRequest.java | 30 ++++ .../api/dto/auth/LoginResponse.java | 31 ++++ .../api/dto/auth/UserInfoResponse.java | 31 ++++ .../api/dto/common/BulkDeleteRequest.java | 22 +++ .../api/dto/common/DropdownOption.java | 22 +++ .../api/dto/common/PageResponse.java | 60 +++++++ .../api/dto/inventory/InventoryRequest.java | 40 +++++ .../api/dto/inventory/InventoryResponse.java | 58 +++++++ .../api/dto/pet/PetRequest.java | 79 +++++++++ .../api/dto/pet/PetResponse.java | 88 ++++++++++ .../api/dto/product/ProductRequest.java | 42 +++++ .../api/dto/product/ProductResponse.java | 51 ++++++ .../ProductSupplierRequest.java | 33 ++++ .../ProductSupplierResponse.java | 42 +++++ .../purchaseorder/PurchaseOrderResponse.java | 61 +++++++ .../api/dto/sale/SaleItemRequest.java | 33 ++++ .../api/dto/sale/SaleItemResponse.java | 51 ++++++ .../api/dto/sale/SaleRequest.java | 51 ++++++ .../api/dto/sale/SaleResponse.java | 89 ++++++++++ .../api/dto/service/ServiceRequest.java | 33 ++++ .../api/dto/service/ServiceResponse.java | 42 +++++ .../api/dto/supplier/SupplierRequest.java | 49 ++++++ .../api/dto/supplier/SupplierResponse.java | 58 +++++++ .../api/dto/user/UserRequest.java | 58 +++++++ .../api/dto/user/UserResponse.java | 60 +++++++ .../api/endpoints/AdoptionApi.java | 43 +++++ .../api/endpoints/AnalyticsApi.java | 22 +++ .../api/endpoints/AppointmentApi.java | 43 +++++ .../api/endpoints/DropdownApi.java | 55 ++++++ .../api/endpoints/InventoryApi.java | 42 +++++ .../petshopdesktop/api/endpoints/PetApi.java | 43 +++++ .../api/endpoints/ProductApi.java | 43 +++++ .../api/endpoints/ProductSupplierApi.java | 43 +++++ .../api/endpoints/PurchaseOrderApi.java | 29 ++++ .../petshopdesktop/api/endpoints/SaleApi.java | 38 ++++ .../api/endpoints/ServiceApi.java | 43 +++++ .../api/endpoints/SupplierApi.java | 43 +++++ .../petshopdesktop/api/endpoints/UserApi.java | 34 ++++ 50 files changed, 2320 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/example/petshopdesktop/api/ApiClient.java create mode 100644 src/main/java/org/example/petshopdesktop/api/ApiConfig.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/adoption/AdoptionRequest.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/adoption/AdoptionResponse.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/analytics/DailySales.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/analytics/DashboardResponse.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/analytics/TopProduct.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/appointment/AppointmentRequest.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/appointment/AppointmentResponse.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/auth/LoginRequest.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/auth/LoginResponse.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/auth/UserInfoResponse.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/common/BulkDeleteRequest.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/common/DropdownOption.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/common/PageResponse.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/inventory/InventoryRequest.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/inventory/InventoryResponse.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/pet/PetRequest.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/pet/PetResponse.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/product/ProductRequest.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/product/ProductResponse.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/productsupplier/ProductSupplierRequest.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/productsupplier/ProductSupplierResponse.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/purchaseorder/PurchaseOrderResponse.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/sale/SaleItemRequest.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/sale/SaleItemResponse.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/sale/SaleRequest.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/sale/SaleResponse.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/service/ServiceRequest.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/service/ServiceResponse.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/supplier/SupplierRequest.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/supplier/SupplierResponse.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/user/UserRequest.java create mode 100644 src/main/java/org/example/petshopdesktop/api/dto/user/UserResponse.java create mode 100644 src/main/java/org/example/petshopdesktop/api/endpoints/AdoptionApi.java create mode 100644 src/main/java/org/example/petshopdesktop/api/endpoints/AnalyticsApi.java create mode 100644 src/main/java/org/example/petshopdesktop/api/endpoints/AppointmentApi.java create mode 100644 src/main/java/org/example/petshopdesktop/api/endpoints/DropdownApi.java create mode 100644 src/main/java/org/example/petshopdesktop/api/endpoints/InventoryApi.java create mode 100644 src/main/java/org/example/petshopdesktop/api/endpoints/PetApi.java create mode 100644 src/main/java/org/example/petshopdesktop/api/endpoints/ProductApi.java create mode 100644 src/main/java/org/example/petshopdesktop/api/endpoints/ProductSupplierApi.java create mode 100644 src/main/java/org/example/petshopdesktop/api/endpoints/PurchaseOrderApi.java create mode 100644 src/main/java/org/example/petshopdesktop/api/endpoints/SaleApi.java create mode 100644 src/main/java/org/example/petshopdesktop/api/endpoints/ServiceApi.java create mode 100644 src/main/java/org/example/petshopdesktop/api/endpoints/SupplierApi.java create mode 100644 src/main/java/org/example/petshopdesktop/api/endpoints/UserApi.java diff --git a/connectionpetstore.properties b/connectionpetstore.properties index 426ecafb..00ffda7d 100644 --- a/connectionpetstore.properties +++ b/connectionpetstore.properties @@ -1,3 +1,4 @@ url=jdbc:mysql://127.0.0.1:3306/Petstoredb?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC user=petapp -password=petapppass \ No newline at end of file +password=petapppass +api.baseUrl=http://localhost:8080 \ No newline at end of file diff --git a/pom.xml b/pom.xml index 3c683c9e..437e7605 100644 --- a/pom.xml +++ b/pom.xml @@ -44,6 +44,27 @@ mysql-connector-j 9.3.0 + + + com.fasterxml.jackson.core + jackson-databind + 2.18.2 + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + 2.18.2 + + + com.fasterxml.jackson.core + jackson-core + 2.18.2 + + + com.fasterxml.jackson.core + jackson-annotations + 2.18.2 + diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index d1f07dd9..d946c327 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -2,6 +2,11 @@ module org.example.petshopdesktop { requires javafx.controls; requires javafx.fxml; requires java.sql; + requires java.net.http; + requires com.fasterxml.jackson.databind; + requires com.fasterxml.jackson.core; + requires com.fasterxml.jackson.annotation; + requires com.fasterxml.jackson.datatype.jsr310; opens org.example.petshopdesktop.DTOs to javafx.base; opens org.example.petshopdesktop.models to javafx.base; @@ -10,6 +15,21 @@ module org.example.petshopdesktop { opens org.example.petshopdesktop.controllers to javafx.fxml; opens org.example.petshopdesktop.auth to javafx.fxml; + opens org.example.petshopdesktop.api.dto.common to com.fasterxml.jackson.databind; + opens org.example.petshopdesktop.api.dto.auth to com.fasterxml.jackson.databind; + opens org.example.petshopdesktop.api.dto.product to com.fasterxml.jackson.databind; + opens org.example.petshopdesktop.api.dto.pet to com.fasterxml.jackson.databind; + opens org.example.petshopdesktop.api.dto.service to com.fasterxml.jackson.databind; + opens org.example.petshopdesktop.api.dto.supplier to com.fasterxml.jackson.databind; + opens org.example.petshopdesktop.api.dto.productsupplier to com.fasterxml.jackson.databind; + opens org.example.petshopdesktop.api.dto.inventory to com.fasterxml.jackson.databind; + opens org.example.petshopdesktop.api.dto.appointment to com.fasterxml.jackson.databind; + opens org.example.petshopdesktop.api.dto.adoption to com.fasterxml.jackson.databind; + opens org.example.petshopdesktop.api.dto.sale to com.fasterxml.jackson.databind; + opens org.example.petshopdesktop.api.dto.user to com.fasterxml.jackson.databind; + opens org.example.petshopdesktop.api.dto.analytics to com.fasterxml.jackson.databind; + opens org.example.petshopdesktop.api.dto.purchaseorder to com.fasterxml.jackson.databind; + exports org.example.petshopdesktop; exports org.example.petshopdesktop.controllers; exports org.example.petshopdesktop.auth; diff --git a/src/main/java/org/example/petshopdesktop/api/ApiClient.java b/src/main/java/org/example/petshopdesktop/api/ApiClient.java new file mode 100644 index 00000000..e8f5a2b4 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/ApiClient.java @@ -0,0 +1,164 @@ +package org.example.petshopdesktop.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.example.petshopdesktop.auth.UserSession; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; + +public class ApiClient { + private static final ApiClient INSTANCE = new ApiClient(); + private final HttpClient httpClient; + private final ObjectMapper objectMapper; + private final String baseUrl; + + private ApiClient() { + this.httpClient = HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(10)) + .build(); + this.objectMapper = new ObjectMapper(); + this.objectMapper.registerModule(new JavaTimeModule()); + this.baseUrl = ApiConfig.getInstance().getBaseUrl(); + } + + public static ApiClient getInstance() { + return INSTANCE; + } + + public T get(String path, Class responseClass) throws Exception { + HttpRequest.Builder builder = HttpRequest.newBuilder() + .uri(URI.create(baseUrl + path)) + .GET() + .timeout(Duration.ofSeconds(30)); + + addAuthHeader(builder); + + HttpRequest request = builder.build(); + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + + return handleResponse(response, responseClass); + } + + public T post(String path, Object requestBody, Class responseClass) throws Exception { + String jsonBody = objectMapper.writeValueAsString(requestBody); + + HttpRequest.Builder builder = HttpRequest.newBuilder() + .uri(URI.create(baseUrl + path)) + .header("Content-Type", "application/json") + .POST(HttpRequest.BodyPublishers.ofString(jsonBody)) + .timeout(Duration.ofSeconds(30)); + + addAuthHeader(builder); + + HttpRequest request = builder.build(); + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + + return handleResponse(response, responseClass); + } + + public T put(String path, Object requestBody, Class responseClass) throws Exception { + String jsonBody = objectMapper.writeValueAsString(requestBody); + + HttpRequest.Builder builder = HttpRequest.newBuilder() + .uri(URI.create(baseUrl + path)) + .header("Content-Type", "application/json") + .PUT(HttpRequest.BodyPublishers.ofString(jsonBody)) + .timeout(Duration.ofSeconds(30)); + + addAuthHeader(builder); + + HttpRequest request = builder.build(); + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + + return handleResponse(response, responseClass); + } + + public void delete(String path) throws Exception { + HttpRequest.Builder builder = HttpRequest.newBuilder() + .uri(URI.create(baseUrl + path)) + .DELETE() + .timeout(Duration.ofSeconds(30)); + + addAuthHeader(builder); + + HttpRequest request = builder.build(); + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + + if (response.statusCode() != 204 && response.statusCode() != 200) { + throw new RuntimeException(parseErrorMessage(response)); + } + } + + public void deleteWithBody(String path, Object requestBody) throws Exception { + String jsonBody = objectMapper.writeValueAsString(requestBody); + + HttpRequest.Builder builder = HttpRequest.newBuilder() + .uri(URI.create(baseUrl + path)) + .header("Content-Type", "application/json") + .method("DELETE", HttpRequest.BodyPublishers.ofString(jsonBody)) + .timeout(Duration.ofSeconds(30)); + + addAuthHeader(builder); + + HttpRequest request = builder.build(); + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + + if (response.statusCode() != 204 && response.statusCode() != 200) { + throw new RuntimeException(parseErrorMessage(response)); + } + } + + private void addAuthHeader(HttpRequest.Builder builder) { + String token = UserSession.getInstance().getJwtToken(); + if (token != null && !token.isEmpty()) { + builder.header("Authorization", "Bearer " + token); + } + } + + private T handleResponse(HttpResponse response, Class responseClass) throws Exception { + int statusCode = response.statusCode(); + + if (statusCode == 200 || statusCode == 201) { + if (response.body() == null || response.body().isEmpty()) { + return null; + } + return objectMapper.readValue(response.body(), responseClass); + } else if (statusCode == 204) { + return null; + } else if (statusCode == 401) { + throw new RuntimeException("Authentication failed. Please log in again."); + } else if (statusCode == 403) { + throw new RuntimeException("Access restricted. You don't have permission to perform this action."); + } else { + throw new RuntimeException(parseErrorMessage(response)); + } + } + + private String parseErrorMessage(HttpResponse response) { + try { + if (response.body() != null && !response.body().isEmpty()) { + var errorNode = objectMapper.readTree(response.body()); + if (errorNode.has("message")) { + return errorNode.get("message").asText(); + } + if (errorNode.has("errors")) { + StringBuilder sb = new StringBuilder(); + errorNode.get("errors").fields().forEachRemaining(entry -> { + sb.append(entry.getValue().asText()).append("\n"); + }); + return sb.toString().trim(); + } + } + } catch (Exception e) { + } + return "Request failed with status " + response.statusCode(); + } + + public ObjectMapper getObjectMapper() { + return objectMapper; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/ApiConfig.java b/src/main/java/org/example/petshopdesktop/api/ApiConfig.java new file mode 100644 index 00000000..3394c653 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/ApiConfig.java @@ -0,0 +1,34 @@ +package org.example.petshopdesktop.api; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +public class ApiConfig { + private static final ApiConfig INSTANCE = new ApiConfig(); + private final String baseUrl; + + private ApiConfig() { + Properties props = new Properties(); + String url = "http://localhost:8080"; + + try (InputStream input = getClass().getClassLoader().getResourceAsStream("connectionpetstore.properties")) { + if (input != null) { + props.load(input); + url = props.getProperty("api.baseUrl", "http://localhost:8080"); + } + } catch (IOException e) { + System.err.println("Failed to load api.baseUrl from properties: " + e.getMessage()); + } + + this.baseUrl = url; + } + + public static ApiConfig getInstance() { + return INSTANCE; + } + + public String getBaseUrl() { + return baseUrl; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/adoption/AdoptionRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/adoption/AdoptionRequest.java new file mode 100644 index 00000000..230d5413 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/adoption/AdoptionRequest.java @@ -0,0 +1,42 @@ +package org.example.petshopdesktop.api.dto.adoption; + +import java.time.LocalDate; + +public class AdoptionRequest { + private Long petId; + private Long customerId; + private LocalDate adoptionDate; + private String adoptionStatus; + + public Long getPetId() { + return petId; + } + + public void setPetId(Long petId) { + this.petId = petId; + } + + public Long getCustomerId() { + return customerId; + } + + public void setCustomerId(Long customerId) { + this.customerId = customerId; + } + + public LocalDate getAdoptionDate() { + return adoptionDate; + } + + public void setAdoptionDate(LocalDate adoptionDate) { + this.adoptionDate = adoptionDate; + } + + public String getAdoptionStatus() { + return adoptionStatus; + } + + public void setAdoptionStatus(String adoptionStatus) { + this.adoptionStatus = adoptionStatus; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/adoption/AdoptionResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/adoption/AdoptionResponse.java new file mode 100644 index 00000000..2466a287 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/adoption/AdoptionResponse.java @@ -0,0 +1,51 @@ +package org.example.petshopdesktop.api.dto.adoption; + +import java.time.LocalDate; + +public class AdoptionResponse { + private Long id; + private String petName; + private String customerName; + private LocalDate adoptionDate; + private String adoptionStatus; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getPetName() { + return petName; + } + + public void setPetName(String petName) { + this.petName = petName; + } + + public String getCustomerName() { + return customerName; + } + + public void setCustomerName(String customerName) { + this.customerName = customerName; + } + + public LocalDate getAdoptionDate() { + return adoptionDate; + } + + public void setAdoptionDate(LocalDate adoptionDate) { + this.adoptionDate = adoptionDate; + } + + public String getAdoptionStatus() { + return adoptionStatus; + } + + public void setAdoptionStatus(String adoptionStatus) { + this.adoptionStatus = adoptionStatus; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/analytics/DailySales.java b/src/main/java/org/example/petshopdesktop/api/dto/analytics/DailySales.java new file mode 100644 index 00000000..602fc8be --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/analytics/DailySales.java @@ -0,0 +1,25 @@ +package org.example.petshopdesktop.api.dto.analytics; + +import java.math.BigDecimal; +import java.time.LocalDate; + +public class DailySales { + private LocalDate date; + private BigDecimal totalSales; + + public LocalDate getDate() { + return date; + } + + public void setDate(LocalDate date) { + this.date = date; + } + + public BigDecimal getTotalSales() { + return totalSales; + } + + public void setTotalSales(BigDecimal totalSales) { + this.totalSales = totalSales; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/analytics/DashboardResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/analytics/DashboardResponse.java new file mode 100644 index 00000000..0618419b --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/analytics/DashboardResponse.java @@ -0,0 +1,61 @@ +package org.example.petshopdesktop.api.dto.analytics; + +import java.math.BigDecimal; +import java.util.List; + +public class DashboardResponse { + private BigDecimal totalRevenue; + private Long totalSales; + private Long totalCustomers; + private Long totalProducts; + private List dailySales; + private List topProducts; + + public BigDecimal getTotalRevenue() { + return totalRevenue; + } + + public void setTotalRevenue(BigDecimal totalRevenue) { + this.totalRevenue = totalRevenue; + } + + public Long getTotalSales() { + return totalSales; + } + + public void setTotalSales(Long totalSales) { + this.totalSales = totalSales; + } + + public Long getTotalCustomers() { + return totalCustomers; + } + + public void setTotalCustomers(Long totalCustomers) { + this.totalCustomers = totalCustomers; + } + + public Long getTotalProducts() { + return totalProducts; + } + + public void setTotalProducts(Long totalProducts) { + this.totalProducts = totalProducts; + } + + public List getDailySales() { + return dailySales; + } + + public void setDailySales(List dailySales) { + this.dailySales = dailySales; + } + + public List getTopProducts() { + return topProducts; + } + + public void setTopProducts(List topProducts) { + this.topProducts = topProducts; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/analytics/TopProduct.java b/src/main/java/org/example/petshopdesktop/api/dto/analytics/TopProduct.java new file mode 100644 index 00000000..bc63265a --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/analytics/TopProduct.java @@ -0,0 +1,33 @@ +package org.example.petshopdesktop.api.dto.analytics; + +import java.math.BigDecimal; + +public class TopProduct { + private String productName; + private Integer quantitySold; + private BigDecimal totalRevenue; + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public Integer getQuantitySold() { + return quantitySold; + } + + public void setQuantitySold(Integer quantitySold) { + this.quantitySold = quantitySold; + } + + public BigDecimal getTotalRevenue() { + return totalRevenue; + } + + public void setTotalRevenue(BigDecimal totalRevenue) { + this.totalRevenue = totalRevenue; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/appointment/AppointmentRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/appointment/AppointmentRequest.java new file mode 100644 index 00000000..e675834c --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/appointment/AppointmentRequest.java @@ -0,0 +1,62 @@ +package org.example.petshopdesktop.api.dto.appointment; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.List; + +public class AppointmentRequest { + private List petIds; + private Long customerId; + private Long serviceId; + private LocalDate appointmentDate; + private LocalTime appointmentTime; + private String appointmentStatus; + + public List getPetIds() { + return petIds; + } + + public void setPetIds(List petIds) { + this.petIds = petIds; + } + + public Long getCustomerId() { + return customerId; + } + + public void setCustomerId(Long customerId) { + this.customerId = customerId; + } + + public Long getServiceId() { + return serviceId; + } + + public void setServiceId(Long serviceId) { + this.serviceId = serviceId; + } + + public LocalDate getAppointmentDate() { + return appointmentDate; + } + + public void setAppointmentDate(LocalDate appointmentDate) { + this.appointmentDate = appointmentDate; + } + + public LocalTime getAppointmentTime() { + return appointmentTime; + } + + public void setAppointmentTime(LocalTime appointmentTime) { + this.appointmentTime = appointmentTime; + } + + public String getAppointmentStatus() { + return appointmentStatus; + } + + public void setAppointmentStatus(String appointmentStatus) { + this.appointmentStatus = appointmentStatus; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/appointment/AppointmentResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/appointment/AppointmentResponse.java new file mode 100644 index 00000000..bbe42bd1 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/appointment/AppointmentResponse.java @@ -0,0 +1,70 @@ +package org.example.petshopdesktop.api.dto.appointment; + +import java.time.LocalDate; +import java.time.LocalTime; + +public class AppointmentResponse { + private Long id; + private String customerName; + private String petNames; + private String serviceName; + private LocalDate appointmentDate; + private LocalTime appointmentTime; + private String appointmentStatus; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getCustomerName() { + return customerName; + } + + public void setCustomerName(String customerName) { + this.customerName = customerName; + } + + public String getPetNames() { + return petNames; + } + + public void setPetNames(String petNames) { + this.petNames = petNames; + } + + public String getServiceName() { + return serviceName; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + public LocalDate getAppointmentDate() { + return appointmentDate; + } + + public void setAppointmentDate(LocalDate appointmentDate) { + this.appointmentDate = appointmentDate; + } + + public LocalTime getAppointmentTime() { + return appointmentTime; + } + + public void setAppointmentTime(LocalTime appointmentTime) { + this.appointmentTime = appointmentTime; + } + + public String getAppointmentStatus() { + return appointmentStatus; + } + + public void setAppointmentStatus(String appointmentStatus) { + this.appointmentStatus = appointmentStatus; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/auth/LoginRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/auth/LoginRequest.java new file mode 100644 index 00000000..89d6a98f --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/auth/LoginRequest.java @@ -0,0 +1,30 @@ +package org.example.petshopdesktop.api.dto.auth; + +public class LoginRequest { + private String username; + private String password; + + public LoginRequest() { + } + + public LoginRequest(String username, String password) { + this.username = username; + this.password = password; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/auth/LoginResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/auth/LoginResponse.java new file mode 100644 index 00000000..18eb8449 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/auth/LoginResponse.java @@ -0,0 +1,31 @@ +package org.example.petshopdesktop.api.dto.auth; + +public class LoginResponse { + private String token; + private String username; + private String role; + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getRole() { + return role; + } + + public void setRole(String role) { + this.role = role; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/auth/UserInfoResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/auth/UserInfoResponse.java new file mode 100644 index 00000000..35192de5 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/auth/UserInfoResponse.java @@ -0,0 +1,31 @@ +package org.example.petshopdesktop.api.dto.auth; + +public class UserInfoResponse { + private Long id; + private String username; + private String role; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getRole() { + return role; + } + + public void setRole(String role) { + this.role = role; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/common/BulkDeleteRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/common/BulkDeleteRequest.java new file mode 100644 index 00000000..d95798ef --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/common/BulkDeleteRequest.java @@ -0,0 +1,22 @@ +package org.example.petshopdesktop.api.dto.common; + +import java.util.List; + +public class BulkDeleteRequest { + private List ids; + + public BulkDeleteRequest() { + } + + public BulkDeleteRequest(List ids) { + this.ids = ids; + } + + public List getIds() { + return ids; + } + + public void setIds(List ids) { + this.ids = ids; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/common/DropdownOption.java b/src/main/java/org/example/petshopdesktop/api/dto/common/DropdownOption.java new file mode 100644 index 00000000..b1f24b9c --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/common/DropdownOption.java @@ -0,0 +1,22 @@ +package org.example.petshopdesktop.api.dto.common; + +public class DropdownOption { + private Long id; + private String label; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/common/PageResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/common/PageResponse.java new file mode 100644 index 00000000..9676a55d --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/common/PageResponse.java @@ -0,0 +1,60 @@ +package org.example.petshopdesktop.api.dto.common; + +import java.util.List; + +public class PageResponse { + private List content; + private int pageNumber; + private int pageSize; + private long totalElements; + private int totalPages; + private boolean last; + + public List getContent() { + return content; + } + + public void setContent(List content) { + this.content = content; + } + + public int getPageNumber() { + return pageNumber; + } + + public void setPageNumber(int pageNumber) { + this.pageNumber = pageNumber; + } + + public int getPageSize() { + return pageSize; + } + + public void setPageSize(int pageSize) { + this.pageSize = pageSize; + } + + public long getTotalElements() { + return totalElements; + } + + public void setTotalElements(long totalElements) { + this.totalElements = totalElements; + } + + public int getTotalPages() { + return totalPages; + } + + public void setTotalPages(int totalPages) { + this.totalPages = totalPages; + } + + public boolean isLast() { + return last; + } + + public void setLast(boolean last) { + this.last = last; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/inventory/InventoryRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/inventory/InventoryRequest.java new file mode 100644 index 00000000..4eb99cd0 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/inventory/InventoryRequest.java @@ -0,0 +1,40 @@ +package org.example.petshopdesktop.api.dto.inventory; + +public class InventoryRequest { + private Long productId; + private Long storeId; + private Integer stockQuantity; + private Integer reorderLevel; + + public Long getProductId() { + return productId; + } + + public void setProductId(Long productId) { + this.productId = productId; + } + + public Long getStoreId() { + return storeId; + } + + public void setStoreId(Long storeId) { + this.storeId = storeId; + } + + public Integer getStockQuantity() { + return stockQuantity; + } + + public void setStockQuantity(Integer stockQuantity) { + this.stockQuantity = stockQuantity; + } + + public Integer getReorderLevel() { + return reorderLevel; + } + + public void setReorderLevel(Integer reorderLevel) { + this.reorderLevel = reorderLevel; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/inventory/InventoryResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/inventory/InventoryResponse.java new file mode 100644 index 00000000..7a9ac8b7 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/inventory/InventoryResponse.java @@ -0,0 +1,58 @@ +package org.example.petshopdesktop.api.dto.inventory; + +public class InventoryResponse { + private Long id; + private String productName; + private String categoryName; + private String storeName; + private Integer stockQuantity; + private Integer reorderLevel; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public String getCategoryName() { + return categoryName; + } + + public void setCategoryName(String categoryName) { + this.categoryName = categoryName; + } + + public String getStoreName() { + return storeName; + } + + public void setStoreName(String storeName) { + this.storeName = storeName; + } + + public Integer getStockQuantity() { + return stockQuantity; + } + + public void setStockQuantity(Integer stockQuantity) { + this.stockQuantity = stockQuantity; + } + + public Integer getReorderLevel() { + return reorderLevel; + } + + public void setReorderLevel(Integer reorderLevel) { + this.reorderLevel = reorderLevel; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/pet/PetRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/pet/PetRequest.java new file mode 100644 index 00000000..a67d3e45 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/pet/PetRequest.java @@ -0,0 +1,79 @@ +package org.example.petshopdesktop.api.dto.pet; + +import java.math.BigDecimal; +import java.time.LocalDate; + +public class PetRequest { + private String petName; + private String species; + private String breed; + private LocalDate dateOfBirth; + private String gender; + private String color; + private BigDecimal price; + private String petStatus; + + public String getPetName() { + return petName; + } + + public void setPetName(String petName) { + this.petName = petName; + } + + public String getSpecies() { + return species; + } + + public void setSpecies(String species) { + this.species = species; + } + + public String getBreed() { + return breed; + } + + public void setBreed(String breed) { + this.breed = breed; + } + + public LocalDate getDateOfBirth() { + return dateOfBirth; + } + + public void setDateOfBirth(LocalDate dateOfBirth) { + this.dateOfBirth = dateOfBirth; + } + + public String getGender() { + return gender; + } + + public void setGender(String gender) { + this.gender = gender; + } + + public String getColor() { + return color; + } + + public void setColor(String color) { + this.color = color; + } + + public BigDecimal getPrice() { + return price; + } + + public void setPrice(BigDecimal price) { + this.price = price; + } + + public String getPetStatus() { + return petStatus; + } + + public void setPetStatus(String petStatus) { + this.petStatus = petStatus; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/pet/PetResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/pet/PetResponse.java new file mode 100644 index 00000000..5565e583 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/pet/PetResponse.java @@ -0,0 +1,88 @@ +package org.example.petshopdesktop.api.dto.pet; + +import java.math.BigDecimal; +import java.time.LocalDate; + +public class PetResponse { + private Long id; + private String petName; + private String species; + private String breed; + private LocalDate dateOfBirth; + private String gender; + private String color; + private BigDecimal price; + private String petStatus; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getPetName() { + return petName; + } + + public void setPetName(String petName) { + this.petName = petName; + } + + public String getSpecies() { + return species; + } + + public void setSpecies(String species) { + this.species = species; + } + + public String getBreed() { + return breed; + } + + public void setBreed(String breed) { + this.breed = breed; + } + + public LocalDate getDateOfBirth() { + return dateOfBirth; + } + + public void setDateOfBirth(LocalDate dateOfBirth) { + this.dateOfBirth = dateOfBirth; + } + + public String getGender() { + return gender; + } + + public void setGender(String gender) { + this.gender = gender; + } + + public String getColor() { + return color; + } + + public void setColor(String color) { + this.color = color; + } + + public BigDecimal getPrice() { + return price; + } + + public void setPrice(BigDecimal price) { + this.price = price; + } + + public String getPetStatus() { + return petStatus; + } + + public void setPetStatus(String petStatus) { + this.petStatus = petStatus; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/product/ProductRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/product/ProductRequest.java new file mode 100644 index 00000000..a51ee4d0 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/product/ProductRequest.java @@ -0,0 +1,42 @@ +package org.example.petshopdesktop.api.dto.product; + +import java.math.BigDecimal; + +public class ProductRequest { + private String productName; + private Long categoryId; + private BigDecimal price; + private String description; + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public Long getCategoryId() { + return categoryId; + } + + public void setCategoryId(Long categoryId) { + this.categoryId = categoryId; + } + + public BigDecimal getPrice() { + return price; + } + + public void setPrice(BigDecimal price) { + this.price = price; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/product/ProductResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/product/ProductResponse.java new file mode 100644 index 00000000..07efa236 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/product/ProductResponse.java @@ -0,0 +1,51 @@ +package org.example.petshopdesktop.api.dto.product; + +import java.math.BigDecimal; + +public class ProductResponse { + private Long id; + private String productName; + private String categoryName; + private BigDecimal price; + private String description; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public String getCategoryName() { + return categoryName; + } + + public void setCategoryName(String categoryName) { + this.categoryName = categoryName; + } + + public BigDecimal getPrice() { + return price; + } + + public void setPrice(BigDecimal price) { + this.price = price; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/productsupplier/ProductSupplierRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/productsupplier/ProductSupplierRequest.java new file mode 100644 index 00000000..e57d3801 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/productsupplier/ProductSupplierRequest.java @@ -0,0 +1,33 @@ +package org.example.petshopdesktop.api.dto.productsupplier; + +import java.math.BigDecimal; + +public class ProductSupplierRequest { + private Long productId; + private Long supplierId; + private BigDecimal supplierPrice; + + public Long getProductId() { + return productId; + } + + public void setProductId(Long productId) { + this.productId = productId; + } + + public Long getSupplierId() { + return supplierId; + } + + public void setSupplierId(Long supplierId) { + this.supplierId = supplierId; + } + + public BigDecimal getSupplierPrice() { + return supplierPrice; + } + + public void setSupplierPrice(BigDecimal supplierPrice) { + this.supplierPrice = supplierPrice; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/productsupplier/ProductSupplierResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/productsupplier/ProductSupplierResponse.java new file mode 100644 index 00000000..4f4ed246 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/productsupplier/ProductSupplierResponse.java @@ -0,0 +1,42 @@ +package org.example.petshopdesktop.api.dto.productsupplier; + +import java.math.BigDecimal; + +public class ProductSupplierResponse { + private Long id; + private String productName; + private String supplierName; + private BigDecimal supplierPrice; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public String getSupplierName() { + return supplierName; + } + + public void setSupplierName(String supplierName) { + this.supplierName = supplierName; + } + + public BigDecimal getSupplierPrice() { + return supplierPrice; + } + + public void setSupplierPrice(BigDecimal supplierPrice) { + this.supplierPrice = supplierPrice; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/purchaseorder/PurchaseOrderResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/purchaseorder/PurchaseOrderResponse.java new file mode 100644 index 00000000..8bc1c13c --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/purchaseorder/PurchaseOrderResponse.java @@ -0,0 +1,61 @@ +package org.example.petshopdesktop.api.dto.purchaseorder; + +import java.math.BigDecimal; +import java.time.LocalDate; + +public class PurchaseOrderResponse { + private Long id; + private String supplierName; + private LocalDate orderDate; + private LocalDate expectedDeliveryDate; + private String orderStatus; + private BigDecimal totalAmount; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getSupplierName() { + return supplierName; + } + + public void setSupplierName(String supplierName) { + this.supplierName = supplierName; + } + + public LocalDate getOrderDate() { + return orderDate; + } + + public void setOrderDate(LocalDate orderDate) { + this.orderDate = orderDate; + } + + public LocalDate getExpectedDeliveryDate() { + return expectedDeliveryDate; + } + + public void setExpectedDeliveryDate(LocalDate expectedDeliveryDate) { + this.expectedDeliveryDate = expectedDeliveryDate; + } + + public String getOrderStatus() { + return orderStatus; + } + + public void setOrderStatus(String orderStatus) { + this.orderStatus = orderStatus; + } + + public BigDecimal getTotalAmount() { + return totalAmount; + } + + public void setTotalAmount(BigDecimal totalAmount) { + this.totalAmount = totalAmount; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleItemRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleItemRequest.java new file mode 100644 index 00000000..a853a608 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleItemRequest.java @@ -0,0 +1,33 @@ +package org.example.petshopdesktop.api.dto.sale; + +import java.math.BigDecimal; + +public class SaleItemRequest { + private Long productId; + private Integer quantity; + private BigDecimal unitPrice; + + public Long getProductId() { + return productId; + } + + public void setProductId(Long productId) { + this.productId = productId; + } + + public Integer getQuantity() { + return quantity; + } + + public void setQuantity(Integer quantity) { + this.quantity = quantity; + } + + public BigDecimal getUnitPrice() { + return unitPrice; + } + + public void setUnitPrice(BigDecimal unitPrice) { + this.unitPrice = unitPrice; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleItemResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleItemResponse.java new file mode 100644 index 00000000..98d989bf --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleItemResponse.java @@ -0,0 +1,51 @@ +package org.example.petshopdesktop.api.dto.sale; + +import java.math.BigDecimal; + +public class SaleItemResponse { + private Long id; + private String productName; + private Integer quantity; + private BigDecimal unitPrice; + private BigDecimal lineTotal; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public Integer getQuantity() { + return quantity; + } + + public void setQuantity(Integer quantity) { + this.quantity = quantity; + } + + public BigDecimal getUnitPrice() { + return unitPrice; + } + + public void setUnitPrice(BigDecimal unitPrice) { + this.unitPrice = unitPrice; + } + + public BigDecimal getLineTotal() { + return lineTotal; + } + + public void setLineTotal(BigDecimal lineTotal) { + this.lineTotal = lineTotal; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleRequest.java new file mode 100644 index 00000000..cb856e06 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleRequest.java @@ -0,0 +1,51 @@ +package org.example.petshopdesktop.api.dto.sale; + +import java.util.List; + +public class SaleRequest { + private Long storeId; + private String paymentMethod; + private List items; + private Boolean isRefund; + private Long originalSaleId; + + public Long getStoreId() { + return storeId; + } + + public void setStoreId(Long storeId) { + this.storeId = storeId; + } + + public String getPaymentMethod() { + return paymentMethod; + } + + public void setPaymentMethod(String paymentMethod) { + this.paymentMethod = paymentMethod; + } + + public List getItems() { + return items; + } + + public void setItems(List items) { + this.items = items; + } + + public Boolean getIsRefund() { + return isRefund; + } + + public void setIsRefund(Boolean isRefund) { + this.isRefund = isRefund; + } + + public Long getOriginalSaleId() { + return originalSaleId; + } + + public void setOriginalSaleId(Long originalSaleId) { + this.originalSaleId = originalSaleId; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleResponse.java new file mode 100644 index 00000000..e2ed8111 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleResponse.java @@ -0,0 +1,89 @@ +package org.example.petshopdesktop.api.dto.sale; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +public class SaleResponse { + private Long id; + private String employeeName; + private String storeName; + private LocalDateTime saleDate; + private BigDecimal totalAmount; + private String paymentMethod; + private Boolean isRefund; + private Long originalSaleId; + private List items; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getEmployeeName() { + return employeeName; + } + + public void setEmployeeName(String employeeName) { + this.employeeName = employeeName; + } + + public String getStoreName() { + return storeName; + } + + public void setStoreName(String storeName) { + this.storeName = storeName; + } + + public LocalDateTime getSaleDate() { + return saleDate; + } + + public void setSaleDate(LocalDateTime saleDate) { + this.saleDate = saleDate; + } + + public BigDecimal getTotalAmount() { + return totalAmount; + } + + public void setTotalAmount(BigDecimal totalAmount) { + this.totalAmount = totalAmount; + } + + public String getPaymentMethod() { + return paymentMethod; + } + + public void setPaymentMethod(String paymentMethod) { + this.paymentMethod = paymentMethod; + } + + public Boolean getIsRefund() { + return isRefund; + } + + public void setIsRefund(Boolean isRefund) { + this.isRefund = isRefund; + } + + public Long getOriginalSaleId() { + return originalSaleId; + } + + public void setOriginalSaleId(Long originalSaleId) { + this.originalSaleId = originalSaleId; + } + + public List getItems() { + return items; + } + + public void setItems(List items) { + this.items = items; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceRequest.java new file mode 100644 index 00000000..11d7659a --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceRequest.java @@ -0,0 +1,33 @@ +package org.example.petshopdesktop.api.dto.service; + +import java.math.BigDecimal; + +public class ServiceRequest { + private String serviceName; + private BigDecimal price; + private String description; + + public String getServiceName() { + return serviceName; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + public BigDecimal getPrice() { + return price; + } + + public void setPrice(BigDecimal price) { + this.price = price; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceResponse.java new file mode 100644 index 00000000..e3e61a08 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceResponse.java @@ -0,0 +1,42 @@ +package org.example.petshopdesktop.api.dto.service; + +import java.math.BigDecimal; + +public class ServiceResponse { + private Long id; + private String serviceName; + private BigDecimal price; + private String description; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getServiceName() { + return serviceName; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + public BigDecimal getPrice() { + return price; + } + + public void setPrice(BigDecimal price) { + this.price = price; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/supplier/SupplierRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/supplier/SupplierRequest.java new file mode 100644 index 00000000..51b31b96 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/supplier/SupplierRequest.java @@ -0,0 +1,49 @@ +package org.example.petshopdesktop.api.dto.supplier; + +public class SupplierRequest { + private String supplierName; + private String contactPerson; + private String phone; + private String email; + private String address; + + public String getSupplierName() { + return supplierName; + } + + public void setSupplierName(String supplierName) { + this.supplierName = supplierName; + } + + public String getContactPerson() { + return contactPerson; + } + + public void setContactPerson(String contactPerson) { + this.contactPerson = contactPerson; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/supplier/SupplierResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/supplier/SupplierResponse.java new file mode 100644 index 00000000..5aebfbab --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/supplier/SupplierResponse.java @@ -0,0 +1,58 @@ +package org.example.petshopdesktop.api.dto.supplier; + +public class SupplierResponse { + private Long id; + private String supplierName; + private String contactPerson; + private String phone; + private String email; + private String address; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getSupplierName() { + return supplierName; + } + + public void setSupplierName(String supplierName) { + this.supplierName = supplierName; + } + + public String getContactPerson() { + return contactPerson; + } + + public void setContactPerson(String contactPerson) { + this.contactPerson = contactPerson; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/user/UserRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/user/UserRequest.java new file mode 100644 index 00000000..faa63bcf --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/user/UserRequest.java @@ -0,0 +1,58 @@ +package org.example.petshopdesktop.api.dto.user; + +public class UserRequest { + private String username; + private String password; + private String firstName; + private String lastName; + private String role; + private Boolean active; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getRole() { + return role; + } + + public void setRole(String role) { + this.role = role; + } + + public Boolean getActive() { + return active; + } + + public void setActive(Boolean active) { + this.active = active; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/dto/user/UserResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/user/UserResponse.java new file mode 100644 index 00000000..74776269 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/dto/user/UserResponse.java @@ -0,0 +1,60 @@ +package org.example.petshopdesktop.api.dto.user; + +import java.time.LocalDateTime; + +public class UserResponse { + private Long id; + private String username; + private String fullName; + private String role; + private Boolean active; + private LocalDateTime createdAt; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getFullName() { + return fullName; + } + + public void setFullName(String fullName) { + this.fullName = fullName; + } + + public String getRole() { + return role; + } + + public void setRole(String role) { + this.role = role; + } + + public Boolean getActive() { + return active; + } + + public void setActive(Boolean active) { + this.active = active; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(LocalDateTime createdAt) { + this.createdAt = createdAt; + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/AdoptionApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/AdoptionApi.java new file mode 100644 index 00000000..f5c0f8e4 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/AdoptionApi.java @@ -0,0 +1,43 @@ +package org.example.petshopdesktop.api.endpoints; + +import com.fasterxml.jackson.core.type.TypeReference; +import org.example.petshopdesktop.api.ApiClient; +import org.example.petshopdesktop.api.dto.adoption.AdoptionRequest; +import org.example.petshopdesktop.api.dto.adoption.AdoptionResponse; +import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest; + +import java.util.List; + +public class AdoptionApi { + private static final AdoptionApi INSTANCE = new AdoptionApi(); + private final ApiClient apiClient; + + private AdoptionApi() { + this.apiClient = ApiClient.getInstance(); + } + + public static AdoptionApi getInstance() { + return INSTANCE; + } + + public List listAdoptions(String query) throws Exception { + String path = "/api/v1/adoptions?page=0&size=1000"; + if (query != null && !query.isEmpty()) { + path += "&q=" + query; + } + String response = apiClient.get(path, String.class); + return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + } + + public AdoptionResponse createAdoption(AdoptionRequest request) throws Exception { + return apiClient.post("/api/v1/adoptions", request, AdoptionResponse.class); + } + + public AdoptionResponse updateAdoption(Long id, AdoptionRequest request) throws Exception { + return apiClient.put("/api/v1/adoptions/" + id, request, AdoptionResponse.class); + } + + public void deleteAdoptions(List ids) throws Exception { + apiClient.deleteWithBody("/api/v1/adoptions", new BulkDeleteRequest(ids)); + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/AnalyticsApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/AnalyticsApi.java new file mode 100644 index 00000000..ebecd9c2 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/AnalyticsApi.java @@ -0,0 +1,22 @@ +package org.example.petshopdesktop.api.endpoints; + +import org.example.petshopdesktop.api.ApiClient; +import org.example.petshopdesktop.api.dto.analytics.DashboardResponse; + +public class AnalyticsApi { + private static final AnalyticsApi INSTANCE = new AnalyticsApi(); + private final ApiClient apiClient; + + private AnalyticsApi() { + this.apiClient = ApiClient.getInstance(); + } + + public static AnalyticsApi getInstance() { + return INSTANCE; + } + + public DashboardResponse getDashboard(int days, int top) throws Exception { + String path = "/api/v1/analytics/dashboard?days=" + days + "&top=" + top; + return apiClient.get(path, DashboardResponse.class); + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/AppointmentApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/AppointmentApi.java new file mode 100644 index 00000000..e7d1410a --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/AppointmentApi.java @@ -0,0 +1,43 @@ +package org.example.petshopdesktop.api.endpoints; + +import com.fasterxml.jackson.core.type.TypeReference; +import org.example.petshopdesktop.api.ApiClient; +import org.example.petshopdesktop.api.dto.appointment.AppointmentRequest; +import org.example.petshopdesktop.api.dto.appointment.AppointmentResponse; +import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest; + +import java.util.List; + +public class AppointmentApi { + private static final AppointmentApi INSTANCE = new AppointmentApi(); + private final ApiClient apiClient; + + private AppointmentApi() { + this.apiClient = ApiClient.getInstance(); + } + + public static AppointmentApi getInstance() { + return INSTANCE; + } + + public List listAppointments(String query) throws Exception { + String path = "/api/v1/appointments?page=0&size=1000"; + if (query != null && !query.isEmpty()) { + path += "&q=" + query; + } + String response = apiClient.get(path, String.class); + return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + } + + public AppointmentResponse createAppointment(AppointmentRequest request) throws Exception { + return apiClient.post("/api/v1/appointments", request, AppointmentResponse.class); + } + + public AppointmentResponse updateAppointment(Long id, AppointmentRequest request) throws Exception { + return apiClient.put("/api/v1/appointments/" + id, request, AppointmentResponse.class); + } + + public void deleteAppointments(List ids) throws Exception { + apiClient.deleteWithBody("/api/v1/appointments", new BulkDeleteRequest(ids)); + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/DropdownApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/DropdownApi.java new file mode 100644 index 00000000..bff7998c --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/DropdownApi.java @@ -0,0 +1,55 @@ +package org.example.petshopdesktop.api.endpoints; + +import com.fasterxml.jackson.core.type.TypeReference; +import org.example.petshopdesktop.api.ApiClient; +import org.example.petshopdesktop.api.dto.common.DropdownOption; + +import java.util.List; + +public class DropdownApi { + private static final DropdownApi INSTANCE = new DropdownApi(); + private final ApiClient apiClient; + + private DropdownApi() { + this.apiClient = ApiClient.getInstance(); + } + + public static DropdownApi getInstance() { + return INSTANCE; + } + + public List getCategories() throws Exception { + String response = apiClient.get("/api/v1/dropdowns/categories", String.class); + return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + } + + public List getProducts() throws Exception { + String response = apiClient.get("/api/v1/dropdowns/products", String.class); + return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + } + + public List getSuppliers() throws Exception { + String response = apiClient.get("/api/v1/dropdowns/suppliers", String.class); + return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + } + + public List getServices() throws Exception { + String response = apiClient.get("/api/v1/dropdowns/services", String.class); + return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + } + + public List getCustomers() throws Exception { + String response = apiClient.get("/api/v1/dropdowns/customers", String.class); + return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + } + + public List getPets() throws Exception { + String response = apiClient.get("/api/v1/dropdowns/pets", String.class); + return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + } + + public List getStores() throws Exception { + String response = apiClient.get("/api/v1/dropdowns/stores", String.class); + return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/InventoryApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/InventoryApi.java new file mode 100644 index 00000000..1712576e --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/InventoryApi.java @@ -0,0 +1,42 @@ +package org.example.petshopdesktop.api.endpoints; + +import com.fasterxml.jackson.core.type.TypeReference; +import org.example.petshopdesktop.api.ApiClient; +import org.example.petshopdesktop.api.dto.inventory.InventoryRequest; +import org.example.petshopdesktop.api.dto.inventory.InventoryResponse; + +import java.util.List; + +public class InventoryApi { + private static final InventoryApi INSTANCE = new InventoryApi(); + private final ApiClient apiClient; + + private InventoryApi() { + this.apiClient = ApiClient.getInstance(); + } + + public static InventoryApi getInstance() { + return INSTANCE; + } + + public List listInventory(String query) throws Exception { + String path = "/api/v1/inventory?page=0&size=1000"; + if (query != null && !query.isEmpty()) { + path += "&q=" + query; + } + String response = apiClient.get(path, String.class); + return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + } + + public InventoryResponse createInventory(InventoryRequest request) throws Exception { + return apiClient.post("/api/v1/inventory", request, InventoryResponse.class); + } + + public InventoryResponse updateInventory(Long id, InventoryRequest request) throws Exception { + return apiClient.put("/api/v1/inventory/" + id, request, InventoryResponse.class); + } + + public void deleteInventory(Long id) throws Exception { + apiClient.delete("/api/v1/inventory/" + id); + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/PetApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/PetApi.java new file mode 100644 index 00000000..73b2c55c --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/PetApi.java @@ -0,0 +1,43 @@ +package org.example.petshopdesktop.api.endpoints; + +import com.fasterxml.jackson.core.type.TypeReference; +import org.example.petshopdesktop.api.ApiClient; +import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest; +import org.example.petshopdesktop.api.dto.pet.PetRequest; +import org.example.petshopdesktop.api.dto.pet.PetResponse; + +import java.util.List; + +public class PetApi { + private static final PetApi INSTANCE = new PetApi(); + private final ApiClient apiClient; + + private PetApi() { + this.apiClient = ApiClient.getInstance(); + } + + public static PetApi getInstance() { + return INSTANCE; + } + + public List listPets(String query) throws Exception { + String path = "/api/v1/pets?page=0&size=1000"; + if (query != null && !query.isEmpty()) { + path += "&q=" + query; + } + String response = apiClient.get(path, String.class); + return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + } + + public PetResponse createPet(PetRequest request) throws Exception { + return apiClient.post("/api/v1/pets", request, PetResponse.class); + } + + public PetResponse updatePet(Long id, PetRequest request) throws Exception { + return apiClient.put("/api/v1/pets/" + id, request, PetResponse.class); + } + + public void deletePets(List ids) throws Exception { + apiClient.deleteWithBody("/api/v1/pets", new BulkDeleteRequest(ids)); + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/ProductApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/ProductApi.java new file mode 100644 index 00000000..3a40ec76 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/ProductApi.java @@ -0,0 +1,43 @@ +package org.example.petshopdesktop.api.endpoints; + +import com.fasterxml.jackson.core.type.TypeReference; +import org.example.petshopdesktop.api.ApiClient; +import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest; +import org.example.petshopdesktop.api.dto.product.ProductRequest; +import org.example.petshopdesktop.api.dto.product.ProductResponse; + +import java.util.List; + +public class ProductApi { + private static final ProductApi INSTANCE = new ProductApi(); + private final ApiClient apiClient; + + private ProductApi() { + this.apiClient = ApiClient.getInstance(); + } + + public static ProductApi getInstance() { + return INSTANCE; + } + + public List listProducts(String query) throws Exception { + String path = "/api/v1/products?page=0&size=1000"; + if (query != null && !query.isEmpty()) { + path += "&q=" + query; + } + String response = apiClient.get(path, String.class); + return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + } + + public ProductResponse createProduct(ProductRequest request) throws Exception { + return apiClient.post("/api/v1/products", request, ProductResponse.class); + } + + public ProductResponse updateProduct(Long id, ProductRequest request) throws Exception { + return apiClient.put("/api/v1/products/" + id, request, ProductResponse.class); + } + + public void deleteProducts(List ids) throws Exception { + apiClient.deleteWithBody("/api/v1/products", new BulkDeleteRequest(ids)); + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/ProductSupplierApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/ProductSupplierApi.java new file mode 100644 index 00000000..b98c3d74 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/ProductSupplierApi.java @@ -0,0 +1,43 @@ +package org.example.petshopdesktop.api.endpoints; + +import com.fasterxml.jackson.core.type.TypeReference; +import org.example.petshopdesktop.api.ApiClient; +import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest; +import org.example.petshopdesktop.api.dto.productsupplier.ProductSupplierRequest; +import org.example.petshopdesktop.api.dto.productsupplier.ProductSupplierResponse; + +import java.util.List; + +public class ProductSupplierApi { + private static final ProductSupplierApi INSTANCE = new ProductSupplierApi(); + private final ApiClient apiClient; + + private ProductSupplierApi() { + this.apiClient = ApiClient.getInstance(); + } + + public static ProductSupplierApi getInstance() { + return INSTANCE; + } + + public List listProductSuppliers(String query) throws Exception { + String path = "/api/v1/product-suppliers?page=0&size=1000"; + if (query != null && !query.isEmpty()) { + path += "&q=" + query; + } + String response = apiClient.get(path, String.class); + return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + } + + public ProductSupplierResponse createProductSupplier(ProductSupplierRequest request) throws Exception { + return apiClient.post("/api/v1/product-suppliers", request, ProductSupplierResponse.class); + } + + public ProductSupplierResponse updateProductSupplier(Long id, ProductSupplierRequest request) throws Exception { + return apiClient.put("/api/v1/product-suppliers/" + id, request, ProductSupplierResponse.class); + } + + public void deleteProductSuppliers(List ids) throws Exception { + apiClient.deleteWithBody("/api/v1/product-suppliers", new BulkDeleteRequest(ids)); + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/PurchaseOrderApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/PurchaseOrderApi.java new file mode 100644 index 00000000..3b9cd558 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/PurchaseOrderApi.java @@ -0,0 +1,29 @@ +package org.example.petshopdesktop.api.endpoints; + +import com.fasterxml.jackson.core.type.TypeReference; +import org.example.petshopdesktop.api.ApiClient; +import org.example.petshopdesktop.api.dto.purchaseorder.PurchaseOrderResponse; + +import java.util.List; + +public class PurchaseOrderApi { + private static final PurchaseOrderApi INSTANCE = new PurchaseOrderApi(); + private final ApiClient apiClient; + + private PurchaseOrderApi() { + this.apiClient = ApiClient.getInstance(); + } + + public static PurchaseOrderApi getInstance() { + return INSTANCE; + } + + public List listPurchaseOrders(String query) throws Exception { + String path = "/api/v1/purchase-orders?page=0&size=1000"; + if (query != null && !query.isEmpty()) { + path += "&q=" + query; + } + String response = apiClient.get(path, String.class); + return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/SaleApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/SaleApi.java new file mode 100644 index 00000000..f1e18733 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/SaleApi.java @@ -0,0 +1,38 @@ +package org.example.petshopdesktop.api.endpoints; + +import com.fasterxml.jackson.core.type.TypeReference; +import org.example.petshopdesktop.api.ApiClient; +import org.example.petshopdesktop.api.dto.sale.SaleRequest; +import org.example.petshopdesktop.api.dto.sale.SaleResponse; + +import java.util.List; + +public class SaleApi { + private static final SaleApi INSTANCE = new SaleApi(); + private final ApiClient apiClient; + + private SaleApi() { + this.apiClient = ApiClient.getInstance(); + } + + public static SaleApi getInstance() { + return INSTANCE; + } + + public List listSales(int page, int size, String query) throws Exception { + String path = "/api/v1/sales?page=" + page + "&size=" + size; + if (query != null && !query.isEmpty()) { + path += "&q=" + query; + } + String response = apiClient.get(path, String.class); + return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + } + + public SaleResponse getSale(Long id) throws Exception { + return apiClient.get("/api/v1/sales/" + id, SaleResponse.class); + } + + public SaleResponse createSale(SaleRequest request) throws Exception { + return apiClient.post("/api/v1/sales", request, SaleResponse.class); + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/ServiceApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/ServiceApi.java new file mode 100644 index 00000000..3ca554f1 --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/ServiceApi.java @@ -0,0 +1,43 @@ +package org.example.petshopdesktop.api.endpoints; + +import com.fasterxml.jackson.core.type.TypeReference; +import org.example.petshopdesktop.api.ApiClient; +import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest; +import org.example.petshopdesktop.api.dto.service.ServiceRequest; +import org.example.petshopdesktop.api.dto.service.ServiceResponse; + +import java.util.List; + +public class ServiceApi { + private static final ServiceApi INSTANCE = new ServiceApi(); + private final ApiClient apiClient; + + private ServiceApi() { + this.apiClient = ApiClient.getInstance(); + } + + public static ServiceApi getInstance() { + return INSTANCE; + } + + public List listServices(String query) throws Exception { + String path = "/api/v1/services?page=0&size=1000"; + if (query != null && !query.isEmpty()) { + path += "&q=" + query; + } + String response = apiClient.get(path, String.class); + return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + } + + public ServiceResponse createService(ServiceRequest request) throws Exception { + return apiClient.post("/api/v1/services", request, ServiceResponse.class); + } + + public ServiceResponse updateService(Long id, ServiceRequest request) throws Exception { + return apiClient.put("/api/v1/services/" + id, request, ServiceResponse.class); + } + + public void deleteServices(List ids) throws Exception { + apiClient.deleteWithBody("/api/v1/services", new BulkDeleteRequest(ids)); + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/SupplierApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/SupplierApi.java new file mode 100644 index 00000000..9fe5eaad --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/SupplierApi.java @@ -0,0 +1,43 @@ +package org.example.petshopdesktop.api.endpoints; + +import com.fasterxml.jackson.core.type.TypeReference; +import org.example.petshopdesktop.api.ApiClient; +import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest; +import org.example.petshopdesktop.api.dto.supplier.SupplierRequest; +import org.example.petshopdesktop.api.dto.supplier.SupplierResponse; + +import java.util.List; + +public class SupplierApi { + private static final SupplierApi INSTANCE = new SupplierApi(); + private final ApiClient apiClient; + + private SupplierApi() { + this.apiClient = ApiClient.getInstance(); + } + + public static SupplierApi getInstance() { + return INSTANCE; + } + + public List listSuppliers(String query) throws Exception { + String path = "/api/v1/suppliers?page=0&size=1000"; + if (query != null && !query.isEmpty()) { + path += "&q=" + query; + } + String response = apiClient.get(path, String.class); + return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + } + + public SupplierResponse createSupplier(SupplierRequest request) throws Exception { + return apiClient.post("/api/v1/suppliers", request, SupplierResponse.class); + } + + public SupplierResponse updateSupplier(Long id, SupplierRequest request) throws Exception { + return apiClient.put("/api/v1/suppliers/" + id, request, SupplierResponse.class); + } + + public void deleteSuppliers(List ids) throws Exception { + apiClient.deleteWithBody("/api/v1/suppliers", new BulkDeleteRequest(ids)); + } +} diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/UserApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/UserApi.java new file mode 100644 index 00000000..54a58c0e --- /dev/null +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/UserApi.java @@ -0,0 +1,34 @@ +package org.example.petshopdesktop.api.endpoints; + +import com.fasterxml.jackson.core.type.TypeReference; +import org.example.petshopdesktop.api.ApiClient; +import org.example.petshopdesktop.api.dto.user.UserRequest; +import org.example.petshopdesktop.api.dto.user.UserResponse; + +import java.util.List; + +public class UserApi { + private static final UserApi INSTANCE = new UserApi(); + private final ApiClient apiClient; + + private UserApi() { + this.apiClient = ApiClient.getInstance(); + } + + public static UserApi getInstance() { + return INSTANCE; + } + + public List listUsers(String query) throws Exception { + String path = "/api/v1/users?page=0&size=1000"; + if (query != null && !query.isEmpty()) { + path += "&q=" + query; + } + String response = apiClient.get(path, String.class); + return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + } + + public UserResponse createUser(UserRequest request) throws Exception { + return apiClient.post("/api/v1/users", request, UserResponse.class); + } +} From 4fc518af07e6a66ebfff0387f051a6415de950ce Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Sat, 7 Mar 2026 13:21:09 -0700 Subject: [PATCH 02/19] Update authentication to use REST API --- .../petshopdesktop/auth/UserSession.java | 31 ++++++-- .../controllers/LoginController.java | 71 +++++++++---------- 2 files changed, 59 insertions(+), 43 deletions(-) diff --git a/src/main/java/org/example/petshopdesktop/auth/UserSession.java b/src/main/java/org/example/petshopdesktop/auth/UserSession.java index 8b34353b..162ad845 100644 --- a/src/main/java/org/example/petshopdesktop/auth/UserSession.java +++ b/src/main/java/org/example/petshopdesktop/auth/UserSession.java @@ -3,11 +3,13 @@ package org.example.petshopdesktop.auth; public class UserSession { private static UserSession instance; - private Integer userId; - private Integer employeeId; + private Long userId; + private Long employeeId; private String username; private String employeeName; private Role role; + private String jwtToken; + private Long storeId; private UserSession() {} @@ -18,12 +20,13 @@ public class UserSession { return instance; } - public void login(int userId, int employeeId, String username, String employeeName, Role role) { + public void login(Long userId, String username, Role role, String jwtToken) { this.userId = userId; - this.employeeId = employeeId; + this.employeeId = userId; this.username = username; - this.employeeName = employeeName; + this.employeeName = username; this.role = role; + this.jwtToken = jwtToken; } public void logout() { @@ -32,13 +35,15 @@ public class UserSession { this.username = null; this.employeeName = null; this.role = null; + this.jwtToken = null; + this.storeId = null; } - public Integer getUserId() { + public Long getUserId() { return userId; } - public Integer getEmployeeId() { + public Long getEmployeeId() { return employeeId; } @@ -54,6 +59,18 @@ public class UserSession { return role; } + public String getJwtToken() { + return jwtToken; + } + + public Long getStoreId() { + return storeId; + } + + public void setStoreId(Long storeId) { + this.storeId = storeId; + } + public boolean isLoggedIn() { return username != null && role != null; } diff --git a/src/main/java/org/example/petshopdesktop/controllers/LoginController.java b/src/main/java/org/example/petshopdesktop/controllers/LoginController.java index 502c7a49..20e34420 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/LoginController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/LoginController.java @@ -10,13 +10,17 @@ import javafx.scene.control.PasswordField; import javafx.scene.control.TextField; import javafx.stage.Modality; import javafx.stage.Stage; +import org.example.petshopdesktop.api.ApiClient; +import org.example.petshopdesktop.api.dto.auth.LoginRequest; +import org.example.petshopdesktop.api.dto.auth.LoginResponse; +import org.example.petshopdesktop.api.dto.auth.UserInfoResponse; +import org.example.petshopdesktop.api.dto.common.DropdownOption; +import org.example.petshopdesktop.api.endpoints.DropdownApi; +import org.example.petshopdesktop.auth.Role; import org.example.petshopdesktop.auth.UserSession; -import org.example.petshopdesktop.database.ConnectionDB; -import org.example.petshopdesktop.database.UserDB; -import org.example.petshopdesktop.models.User; import org.example.petshopdesktop.util.ActivityLogger; -import java.sql.SQLException; +import java.util.List; public class LoginController { @@ -32,15 +36,6 @@ public class LoginController { @FXML public void initialize() { lblError.setText(""); - try { - ConnectionDB.getConnection().close(); - try { - UserDB.initializeTable(); - } catch (Exception ignored) { - } - } catch (Exception e) { - lblError.setText("Database is not connected. Check Docker and connectionpetstore.properties."); - } } @FXML @@ -54,39 +49,43 @@ public class LoginController { } try { - User user = UserDB.authenticate(username, password); - if (user == null) { - lblError.setText("Invalid username or password."); - txtPassword.clear(); - return; + ApiClient apiClient = ApiClient.getInstance(); + + LoginRequest loginRequest = new LoginRequest(username, password); + LoginResponse loginResponse = apiClient.post("/api/v1/auth/login", loginRequest, LoginResponse.class); + + String token = loginResponse.getToken(); + String roleStr = loginResponse.getRole(); + Role role = Role.valueOf(roleStr.toUpperCase()); + + UserSession.getInstance().login(null, username, role, token); + + UserInfoResponse userInfo = apiClient.get("/api/v1/auth/me", UserInfoResponse.class); + UserSession.getInstance().login(userInfo.getId(), username, role, token); + + List stores = DropdownApi.getInstance().getStores(); + if (!stores.isEmpty()) { + UserSession.getInstance().setStoreId(stores.get(0).getId()); } - UserSession.getInstance().login( - user.getUserId(), - user.getEmployeeId(), - user.getUsername(), - user.getEmployeeFullName(), - user.getRole() - ); openMainLayout(); - } catch (SQLException e) { + } catch (Exception e) { ActivityLogger.getInstance().logException( "LoginController.btnLoginClicked", e, "Authentication attempt for username: " + username); - String msg = e.getMessage() == null ? "" : e.getMessage().toLowerCase(); - if (msg.contains("doesn't exist") || msg.contains("unknown database") || msg.contains("access denied")) { - lblError.setText("Database error. Check Docker and connectionpetstore.properties."); + + String errorMsg = e.getMessage(); + if (errorMsg != null && errorMsg.contains("Authentication failed")) { + lblError.setText("Invalid username or password."); + txtPassword.clear(); + } else if (e.getCause() instanceof java.net.ConnectException || + e instanceof java.net.http.HttpConnectTimeoutException) { + lblError.setText("Backend is not reachable, check backend docker compose and port 8080."); } else { - lblError.setText("Login failed. Check username and password."); + lblError.setText(errorMsg != null ? errorMsg : "Login failed. Please try again."); } - } catch (RuntimeException e) { - ActivityLogger.getInstance().logException( - "LoginController.btnLoginClicked", - e, - "Database connection"); - lblError.setText("Database is not connected. Check Docker and connectionpetstore.properties."); } } From 58e29f307e565a1ebfa10b90dbe74170cae48a51 Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Sat, 7 Mar 2026 13:23:16 -0700 Subject: [PATCH 03/19] Migrate Product controllers to REST API --- .../controllers/ProductController.java | 152 +++++++++--------- .../ProductDialogController.java | 86 +++++----- 2 files changed, 112 insertions(+), 126 deletions(-) diff --git a/src/main/java/org/example/petshopdesktop/controllers/ProductController.java b/src/main/java/org/example/petshopdesktop/controllers/ProductController.java index abc38be7..90cc0775 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/ProductController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/ProductController.java @@ -1,5 +1,6 @@ package org.example.petshopdesktop.controllers; +import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.ActionEvent; @@ -11,18 +12,16 @@ import javafx.scene.control.cell.PropertyValueFactory; import javafx.stage.Modality; import javafx.stage.Stage; import org.example.petshopdesktop.DTOs.ProductDTO; +import org.example.petshopdesktop.api.dto.product.ProductResponse; +import org.example.petshopdesktop.api.endpoints.ProductApi; import org.example.petshopdesktop.controllers.dialogcontrollers.ProductDialogController; -import org.example.petshopdesktop.controllers.dialogcontrollers.SupplierDialogController; -import org.example.petshopdesktop.database.ProductDB; -import org.example.petshopdesktop.database.SupplierDB; -import org.example.petshopdesktop.models.Product; -import org.example.petshopdesktop.models.Supplier; import org.example.petshopdesktop.util.ActivityLogger; import java.io.IOException; -import java.sql.SQLException; -import java.sql.SQLIntegrityConstraintViolationException; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; +import java.util.stream.Collectors /** * The controller for any operations in the products view @@ -110,22 +109,27 @@ public class ProductController { * Display the productDTO to table view */ private void displayProduct(){ - //Erase old content - data.clear(); + new Thread(() -> { + try { + List products = ProductApi.getInstance().listProducts(null); + List productDTOs = products.stream() + .map(this::mapToProductDTO) + .collect(Collectors.toList()); - //get Products from database - try{ - data = ProductDB.getProductDTO(); - } catch (SQLException e) { - System.out.println("Error while fetching table data: " + e.getMessage()); - ActivityLogger.getInstance().logException( - "ProductController.displayProduct", - e, - "Fetching product data for table display"); - } - - //put data in the table - tvProducts.setItems(data); + Platform.runLater(() -> { + data.setAll(productDTOs); + tvProducts.setItems(data); + }); + } catch (Exception e) { + Platform.runLater(() -> { + System.out.println("Error while fetching table data: " + e.getMessage()); + ActivityLogger.getInstance().logException( + "ProductController.displayProduct", + e, + "Fetching product data for table display"); + }); + } + }).start(); } /** @@ -160,48 +164,24 @@ public class ProductController { //if confirmed, start deletion if (result.isPresent() && result.get() == ButtonType.OK) { - int successCount = 0; - int failCount = 0; - StringBuilder errors = new StringBuilder(); + List ids = selectedProducts.stream() + .map(p -> (long) p.getProdId()) + .collect(Collectors.toList()); - for (ProductDTO product : selectedProducts) { - try{ - int numRows = ProductDB.deleteProduct(product.getProdId()); - if (numRows > 0) { - successCount++; - } else { - failCount++; - } - } - catch (SQLIntegrityConstraintViolationException e){ - ActivityLogger.getInstance().logException( - "ProductController.btnDeleteClicked", - e, - String.format("Attempting to delete product ID %d - foreign key constraint", product.getProdId())); - failCount++; - errors.append("Product '").append(product.getProdName()).append("' is referenced in another table\n"); - } - catch (SQLException e) { - ActivityLogger.getInstance().logException( - "ProductController.btnDeleteClicked", - e, - String.format("Attempting to delete product ID %d", product.getProdId())); - failCount++; - errors.append("Failed to delete '").append(product.getProdName()).append("'\n"); - } - } - - //show results - if (failCount > 0) { - Alert alert = new Alert(Alert.AlertType.WARNING); - alert.setHeaderText("Delete Operation Completed with Errors"); - alert.setContentText(String.format("Deleted: %d\nFailed: %d\n\n%s", - successCount, failCount, errors.toString())); - alert.showAndWait(); - } else if (successCount > 0) { + try { + ProductApi.getInstance().deleteProducts(ids); Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setHeaderText("Database Operation Confirmed"); - alert.setContentText("Successfully deleted " + successCount + " product(s)"); + alert.setContentText("Successfully deleted " + ids.size() + " product(s)"); + alert.showAndWait(); + } catch (Exception e) { + ActivityLogger.getInstance().logException( + "ProductController.btnDeleteClicked", + e, + "Deleting products"); + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Delete Operation Failed"); + alert.setContentText(e.getMessage()); alert.showAndWait(); } @@ -233,22 +213,30 @@ public class ProductController { * @param filter word to filter table */ private void displayFilteredProduct(String filter){ - data.clear(); - try{ - if (txtSearch.getText() == null || txtSearch.getText().isEmpty()){ - displayProduct(); //If search bar is empty just display everything - } - else{ - //Filter the using the keyword - data = ProductDB.getFilteredProductDTOs(filter); - tvProducts.setItems(data); - } - } catch (Exception e) { - System.out.println("Error while fetching table data: " + e.getMessage()); - ActivityLogger.getInstance().logException( - "ProductController.displayFilteredProduct", - e, - String.format("Filtering products with keyword: %s", filter)); + if (txtSearch.getText() == null || txtSearch.getText().isEmpty()){ + displayProduct(); + } else { + new Thread(() -> { + try { + List products = ProductApi.getInstance().listProducts(filter); + List productDTOs = products.stream() + .map(this::mapToProductDTO) + .collect(Collectors.toList()); + + Platform.runLater(() -> { + data.setAll(productDTOs); + tvProducts.setItems(data); + }); + } catch (Exception e) { + Platform.runLater(() -> { + System.out.println("Error while fetching table data: " + e.getMessage()); + ActivityLogger.getInstance().logException( + "ProductController.displayFilteredProduct", + e, + String.format("Filtering products with keyword: %s", filter)); + }); + } + }).start(); } } @@ -297,4 +285,14 @@ public class ProductController { txtSearch.setText(""); } + private ProductDTO mapToProductDTO(ProductResponse response) { + ProductDTO dto = new ProductDTO(); + dto.setProdId(response.getId().intValue()); + dto.setProdName(response.getProductName()); + dto.setProdPrice(response.getPrice().doubleValue()); + dto.setCategoryName(response.getCategoryName()); + dto.setProdDesc(response.getDescription()); + return dto; + } + } diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductDialogController.java index 5ad23f81..a63216be 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductDialogController.java @@ -10,15 +10,14 @@ import javafx.scene.input.MouseEvent; import javafx.stage.Stage; import org.example.petshopdesktop.DTOs.ProductDTO; import org.example.petshopdesktop.Validator; -import org.example.petshopdesktop.database.CategoryDB; -import org.example.petshopdesktop.database.ProductDB; -import org.example.petshopdesktop.models.Category; -import org.example.petshopdesktop.models.Product; -import org.example.petshopdesktop.models.Supplier; +import org.example.petshopdesktop.api.dto.common.DropdownOption; +import org.example.petshopdesktop.api.dto.product.ProductRequest; +import org.example.petshopdesktop.api.endpoints.DropdownApi; +import org.example.petshopdesktop.api.endpoints.ProductApi; import org.example.petshopdesktop.util.ActivityLogger; -import java.sql.SQLException; -import java.util.ArrayList; +import java.math.BigDecimal; +import java.util.List public class ProductDialogController { @@ -29,7 +28,7 @@ public class ProductDialogController { private Button btnSave; @FXML - private ComboBox cbProdCategory; + private ComboBox cbProdCategory; @FXML private Label lblMode; @@ -70,11 +69,10 @@ public class ProductDialogController { //Set up combobox for selecting category try { - //set up combobox - ObservableList categories = FXCollections.observableArrayList(); //empty list - categories = CategoryDB.getCategories(); - cbProdCategory.setItems(categories); - } catch (SQLException e) { + List categories = DropdownApi.getInstance().getCategories(); + ObservableList categoriesObs = FXCollections.observableArrayList(categories); + cbProdCategory.setItems(categoriesObs); + } catch (Exception e) { ActivityLogger.getInstance().logException( "ProductDialogController.initialize", e, @@ -108,45 +106,35 @@ public class ProductDialogController { //Check Validation (format) errorMsg += Validator.isNonNegativeDouble(txtProdPrice.getText(), "Product Price"); - if (errorMsg.isEmpty()) { //no validation errors detected - Product product = collectProduct(); //get product info - if (mode.equals("Add")){ //add mode - try{ - numRow = ProductDB.insertProduct(product); - } catch (SQLException e) { - ActivityLogger.getInstance().logException( - "ProductDialogController.buttonSaveClicked", - e, - "Inserting new product record"); - throw new RuntimeException(e); - } - } - else { //edit - try{ - numRow = ProductDB.updateProduct(product.getProdId(),product); - } catch (SQLException e) { - ActivityLogger.getInstance().logException( - "ProductDialogController.buttonSaveClicked", - e, - "Updating product with ID: " + product.getProdId()); - throw new RuntimeException(e); - } - } + if (errorMsg.isEmpty()) { + try { + ProductRequest request = new ProductRequest(); + request.setProductName(txtProdName.getText()); + request.setPrice(new BigDecimal(txtProdPrice.getText())); + request.setCategoryId(cbProdCategory.getSelectionModel().getSelectedItem().getId()); + request.setDescription(txtProdDesc.getText()); + + if (mode.equals("Add")) { + ProductApi.getInstance().createProduct(request); + } else { + Long productId = Long.parseLong(lblProdId.getText().split(": ")[1]); + ProductApi.getInstance().updateProduct(productId, request); + } - //if no rows were affected then there was an error (prompt user of error) - if (numRow == 0){ - Alert alert = new Alert(Alert.AlertType.ERROR); - alert.setHeaderText("Database Operation Error"); - alert.setContentText(mode + " failed"); - alert.showAndWait(); - } - else { - //tell the user operation was successful Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setHeaderText("Saved"); alert.setContentText(mode + " succeeded"); alert.showAndWait(); closeStage(mouseEvent); + } catch (Exception e) { + ActivityLogger.getInstance().logException( + "ProductDialogController.buttonSaveClicked", + e, + mode + " product"); + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Database Operation Error"); + alert.setContentText(e.getMessage()); + alert.showAndWait(); } } else{ //Display validation errors @@ -190,10 +178,10 @@ public class ProductDialogController { txtProdDesc.setText(product.getProdDesc()); txtProdPrice.setText(product.getProdPrice() + ""); - //get the right combobox selection - for (Category category : cbProdCategory.getItems()) { - if(category.getCategoryId() == product.getCategoryId()){ + for (DropdownOption category : cbProdCategory.getItems()) { + if(category.getLabel().equals(product.getCategoryName())){ cbProdCategory.getSelectionModel().select(category); + break; } } From 87f616d08e437b958b939c8715258e9a41498d99 Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Sat, 7 Mar 2026 13:28:45 -0700 Subject: [PATCH 04/19] Migrate Pet controllers to REST API --- .../controllers/PetController.java | 153 ++++++++++-------- .../controllers/ProductController.java | 17 +- .../PetDialogController.java | 86 ++++------ .../ProductDialogController.java | 24 +-- 4 files changed, 125 insertions(+), 155 deletions(-) diff --git a/src/main/java/org/example/petshopdesktop/controllers/PetController.java b/src/main/java/org/example/petshopdesktop/controllers/PetController.java index 4874bea7..1ded3b4c 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/PetController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/PetController.java @@ -1,5 +1,6 @@ package org.example.petshopdesktop.controllers; +import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.ActionEvent; @@ -10,16 +11,18 @@ import javafx.scene.control.*; import javafx.scene.control.cell.PropertyValueFactory; import javafx.stage.Modality; import javafx.stage.Stage; +import org.example.petshopdesktop.api.dto.pet.PetResponse; +import org.example.petshopdesktop.api.endpoints.PetApi; import org.example.petshopdesktop.controllers.dialogcontrollers.PetDialogController; -import org.example.petshopdesktop.database.PetDB; -import org.example.petshopdesktop.database.ProductDB; import org.example.petshopdesktop.models.Pet; import org.example.petshopdesktop.util.ActivityLogger; import java.io.IOException; -import java.sql.SQLException; -import java.sql.SQLIntegrityConstraintViolationException; +import java.time.LocalDate; +import java.time.Period; +import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; public class PetController { @@ -83,48 +86,24 @@ public class PetController { //if confirmed, start deletion if (result.isPresent() && result.get() == ButtonType.OK) { - int successCount = 0; - int failCount = 0; - StringBuilder errors = new StringBuilder(); + List ids = selectedPets.stream() + .map(p -> (long) p.getPetId()) + .collect(Collectors.toList()); - for (Pet pet : selectedPets) { - try{ - int numRows = PetDB.deletePet(pet.getPetId()); - if (numRows > 0) { - successCount++; - } else { - failCount++; - } - } - catch (SQLIntegrityConstraintViolationException e){ - ActivityLogger.getInstance().logException( - "PetController.btnDeleteClicked", - e, - String.format("Attempting to delete pet ID %d - foreign key constraint", pet.getPetId())); - failCount++; - errors.append("Pet '").append(pet.getPetName()).append("' is referenced in another table\n"); - } - catch (SQLException e) { - ActivityLogger.getInstance().logException( - "PetController.btnDeleteClicked", - e, - String.format("Attempting to delete pet ID %d", pet.getPetId())); - failCount++; - errors.append("Failed to delete '").append(pet.getPetName()).append("'\n"); - } - } - - //show results - if (failCount > 0) { - Alert alert = new Alert(Alert.AlertType.WARNING); - alert.setHeaderText("Delete Operation Completed with Errors"); - alert.setContentText(String.format("Deleted: %d\nFailed: %d\n\n%s", - successCount, failCount, errors.toString())); - alert.showAndWait(); - } else if (successCount > 0) { + try { + PetApi.getInstance().deletePets(ids); Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setHeaderText("Database Operation Confirmed"); - alert.setContentText("Successfully deleted " + successCount + " pet(s)"); + alert.setContentText("Successfully deleted " + ids.size() + " pet(s)"); + alert.showAndWait(); + } catch (Exception e) { + ActivityLogger.getInstance().logException( + "PetController.btnDeleteClicked", + e, + "Deleting pets"); + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Delete Operation Failed"); + alert.setContentText(e.getMessage()); alert.showAndWait(); } @@ -187,39 +166,55 @@ public class PetController { } private void displayFilteredPet(String filter) { - data.clear(); - try{ - if (txtSearch.getText() == null || txtSearch.getText().isEmpty()){ - displayPets(); - } - else { - data = PetDB.getFilteredPets(filter); - tvPets.setItems(data); - } - } catch (Exception e) { - ActivityLogger.getInstance().logException( - "PetController.displayFilteredPet", - e, - "Filtering pets with filter: " + filter); - System.out.println("Error while fetching table data: " + e.getMessage()); + if (txtSearch.getText() == null || txtSearch.getText().isEmpty()){ + displayPets(); + } else { + new Thread(() -> { + try { + List pets = PetApi.getInstance().listPets(filter); + List petList = pets.stream() + .map(this::mapToPet) + .collect(Collectors.toList()); + + Platform.runLater(() -> { + data.setAll(petList); + tvPets.setItems(data); + }); + } catch (Exception e) { + Platform.runLater(() -> { + System.out.println("Error while fetching table data: " + e.getMessage()); + ActivityLogger.getInstance().logException( + "PetController.displayFilteredPet", + e, + String.format("Filtering pets with keyword: %s", filter)); + }); + } + }).start(); } } private void displayPets() { - data.clear(); + new Thread(() -> { + try { + List pets = PetApi.getInstance().listPets(null); + List petList = pets.stream() + .map(this::mapToPet) + .collect(Collectors.toList()); - try{ - data = PetDB.getPets(); - } - catch(SQLException e){ - ActivityLogger.getInstance().logException( - "PetController.displayPets", - e, - "Fetching pet data for table display"); - System.out.println("Error while fetching table data: " + e.getMessage()); - } - - tvPets.setItems(data); + Platform.runLater(() -> { + data.setAll(petList); + tvPets.setItems(data); + }); + } catch (Exception e) { + Platform.runLater(() -> { + System.out.println("Error while fetching table data: " + e.getMessage()); + ActivityLogger.getInstance().logException( + "PetController.displayPets", + e, + "Fetching pet data for table display"); + }); + } + }).start(); } private void openDialog(Pet pet, String mode){ @@ -261,4 +256,20 @@ public class PetController { txtSearch.setText(""); } + private Pet mapToPet(PetResponse response) { + int age = 0; + if (response.getDateOfBirth() != null) { + age = Period.between(response.getDateOfBirth(), LocalDate.now()).getYears(); + } + return new Pet( + response.getId().intValue(), + response.getPetName(), + response.getSpecies(), + response.getBreed(), + age, + response.getPetStatus(), + response.getPrice().doubleValue() + ); + } + } \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/controllers/ProductController.java b/src/main/java/org/example/petshopdesktop/controllers/ProductController.java index 90cc0775..f913f1be 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/ProductController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/ProductController.java @@ -21,7 +21,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Optional; -import java.util.stream.Collectors +import java.util.stream.Collectors; /** * The controller for any operations in the products view @@ -286,13 +286,14 @@ public class ProductController { } private ProductDTO mapToProductDTO(ProductResponse response) { - ProductDTO dto = new ProductDTO(); - dto.setProdId(response.getId().intValue()); - dto.setProdName(response.getProductName()); - dto.setProdPrice(response.getPrice().doubleValue()); - dto.setCategoryName(response.getCategoryName()); - dto.setProdDesc(response.getDescription()); - return dto; + return new ProductDTO( + response.getId().intValue(), + response.getProductName(), + response.getPrice().doubleValue(), + 0, + response.getCategoryName(), + response.getDescription() + ); } } diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/PetDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/PetDialogController.java index 45ad7eab..d41790dc 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/PetDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/PetDialogController.java @@ -8,14 +8,15 @@ import javafx.scene.Node; import javafx.scene.control.*; import javafx.scene.input.MouseEvent; import javafx.stage.Stage; -import org.example.petshopdesktop.DTOs.ProductDTO; import org.example.petshopdesktop.Validator; -import org.example.petshopdesktop.database.PetDB; -import org.example.petshopdesktop.models.Category; +import org.example.petshopdesktop.api.dto.pet.PetRequest; +import org.example.petshopdesktop.api.dto.pet.PetResponse; +import org.example.petshopdesktop.api.endpoints.PetApi; import org.example.petshopdesktop.models.Pet; import org.example.petshopdesktop.util.ActivityLogger; -import java.sql.SQLException; +import java.math.BigDecimal; +import java.time.LocalDate; public class PetDialogController { @@ -77,7 +78,6 @@ public class PetDialogController { } private void buttonSaveClicked(MouseEvent mouseEvent) { - int numRow = 0; String errorMsg = ""; //Check validation (input required) @@ -102,46 +102,30 @@ public class PetDialogController { errorMsg += Validator.isNonNegativeInteger(txtPetAge.getText(), "Age"); if(errorMsg.isEmpty()){ - Pet pet = collectPet(); - if(mode.equals("Add")) { - try{ - numRow = PetDB.insertPet(pet); + PetRequest request = buildPetRequest(); + try { + if(mode.equals("Add")) { + PetApi.getInstance().createPet(request); + } else { + Long petId = Long.parseLong(lblPetId.getText().split(": ")[1]); + PetApi.getInstance().updatePet(petId, request); } - catch (SQLException e) { - ActivityLogger.getInstance().logException( - "PetDialogController.buttonSaveClicked", - e, - "Inserting new pet record"); - throw new RuntimeException(e); - } - } - else { - try { - numRow = PetDB.updatePet(pet.getPetId(), pet); - } - catch (SQLException e) { - ActivityLogger.getInstance().logException( - "PetDialogController.buttonSaveClicked", - e, - "Updating pet with ID: " + pet.getPetId()); - throw new RuntimeException(e); - } - } - //if no rows were affected then there was an error (prompt user of error) - if (numRow == 0){ - Alert alert = new Alert(Alert.AlertType.ERROR); - alert.setHeaderText("Database Operation Error"); - alert.setContentText(mode + " failed"); - alert.showAndWait(); - } - else { //tell the user operation was successful Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setHeaderText("Saved"); alert.setContentText(mode + " succeeded"); alert.showAndWait(); closeStage(mouseEvent); + } catch (Exception e) { + ActivityLogger.getInstance().logException( + "PetDialogController.buttonSaveClicked", + e, + mode + " pet record"); + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Operation Error"); + alert.setContentText(mode + " failed: " + e.getMessage()); + alert.showAndWait(); } } else{ @@ -152,23 +136,19 @@ public class PetDialogController { } } - private Pet collectPet() { - int petId =0; - Pet pet = null; + private PetRequest buildPetRequest() { + PetRequest request = new PetRequest(); + request.setPetName(txtPetName.getText()); + request.setSpecies(txtPetSpecies.getText()); + request.setBreed(txtPetBreed.getText()); + request.setPetStatus(cbPetStatus.getValue()); + request.setPrice(new BigDecimal(txtPetPrice.getText())); - if(lblPetId.isVisible()){ - petId = Integer.parseInt(lblPetId.getText().split(": ")[1]); - } - pet = new Pet( - petId, - txtPetName.getText(), - txtPetSpecies.getText(), - txtPetBreed.getText(), - Integer.parseInt(txtPetAge.getText()), - cbPetStatus.getValue(), - Double.parseDouble(txtPetPrice.getText()) - ); - return pet; + int age = Integer.parseInt(txtPetAge.getText()); + LocalDate dateOfBirth = LocalDate.now().minusYears(age); + request.setDateOfBirth(dateOfBirth); + + return request; } private void closeStage(MouseEvent mouseEvent) { diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductDialogController.java index a63216be..298478aa 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductDialogController.java @@ -17,7 +17,7 @@ import org.example.petshopdesktop.api.endpoints.ProductApi; import org.example.petshopdesktop.util.ActivityLogger; import java.math.BigDecimal; -import java.util.List +import java.util.List; public class ProductDialogController { @@ -145,28 +145,6 @@ public class ProductDialogController { } } - /** - * Collect the product info - * @return product info with the id or the new product - */ - private Product collectProduct(){ - int prodId = 0; - Product product = null; - - if(lblProdId.isVisible()){ //Edit mode - //get product id from lblId (split the string so we only get the int) - prodId = Integer.parseInt(lblProdId.getText().split(": ")[1]); - } - product = new Product( - prodId, - txtProdName.getText(), - Double.parseDouble(txtProdPrice.getText()), - cbProdCategory.getSelectionModel().getSelectedItem().getCategoryId(), - txtProdDesc.getText() - ); - return product; - } - /** * Display the product data in text fields and combobox * @param product the product entity containing data to display From 2b8cd222048c6374787f98284753fefc2e248cbd Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Sat, 7 Mar 2026 17:02:53 -0700 Subject: [PATCH 05/19] Migrate all controllers to REST API --- .../petshopdesktop/DTOs/PurchaseOrderDTO.java | 8 +- .../ProductSupplierResponse.java | 18 ++ .../controllers/AdoptionController.java | 148 +++++----- .../controllers/AnalyticsController.java | 124 ++++++--- .../controllers/AppointmentController.java | 134 +++++---- .../controllers/InventoryController.java | 179 ++++++------ .../ProductSupplierController.java | 155 +++++------ .../controllers/PurchaseOrderController.java | 51 +++- .../controllers/SaleController.java | 153 ++++++---- .../controllers/ServiceController.java | 262 +++++++++--------- .../controllers/StaffAccountsController.java | 64 ++++- .../controllers/SupplierController.java | 150 +++++----- .../AdoptionDialogController.java | 197 +++++-------- .../AppointmentDialogController.java | 172 +++++++----- .../ProductSupplierDialogController.java | 241 ++++++++-------- .../RefundDialogController.java | 81 +++--- .../ServiceDialogController.java | 19 +- .../StaffRegisterDialogController.java | 69 ++--- .../SupplierDialogController.java | 82 ++---- .../petshopdesktop/models/Adoption.java | 11 +- .../petshopdesktop/models/Inventory.java | 35 ++- .../petshopdesktop/models/PurchaseOrder.java | 41 ++- .../petshopdesktop/models/StaffAccount.java | 10 +- 23 files changed, 1308 insertions(+), 1096 deletions(-) diff --git a/src/main/java/org/example/petshopdesktop/DTOs/PurchaseOrderDTO.java b/src/main/java/org/example/petshopdesktop/DTOs/PurchaseOrderDTO.java index 11c5d330..acc28e2a 100644 --- a/src/main/java/org/example/petshopdesktop/DTOs/PurchaseOrderDTO.java +++ b/src/main/java/org/example/petshopdesktop/DTOs/PurchaseOrderDTO.java @@ -4,21 +4,21 @@ import javafx.beans.property.*; public class PurchaseOrderDTO { - private IntegerProperty purchaseOrderId; + private LongProperty purchaseOrderId; private StringProperty supplierName; private StringProperty orderDate; private StringProperty status; - public PurchaseOrderDTO(int id, String supplierName, + public PurchaseOrderDTO(long id, String supplierName, String orderDate, String status) { - this.purchaseOrderId = new SimpleIntegerProperty(id); + this.purchaseOrderId = new SimpleLongProperty(id); this.supplierName = new SimpleStringProperty(supplierName); this.orderDate = new SimpleStringProperty(orderDate); this.status = new SimpleStringProperty(status); } - public int getPurchaseOrderId() { return purchaseOrderId.get(); } + public long getPurchaseOrderId() { return purchaseOrderId.get(); } public String getSupplierName() { return supplierName.get(); } public String getOrderDate() { return orderDate.get(); } public String getStatus() { return status.get(); } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/productsupplier/ProductSupplierResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/productsupplier/ProductSupplierResponse.java index 4f4ed246..55478763 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/productsupplier/ProductSupplierResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/productsupplier/ProductSupplierResponse.java @@ -4,6 +4,8 @@ import java.math.BigDecimal; public class ProductSupplierResponse { private Long id; + private Long productId; + private Long supplierId; private String productName; private String supplierName; private BigDecimal supplierPrice; @@ -16,6 +18,22 @@ public class ProductSupplierResponse { this.id = id; } + public Long getProductId() { + return productId; + } + + public void setProductId(Long productId) { + this.productId = productId; + } + + public Long getSupplierId() { + return supplierId; + } + + public void setSupplierId(Long supplierId) { + this.supplierId = supplierId; + } + public String getProductName() { return productName; } diff --git a/src/main/java/org/example/petshopdesktop/controllers/AdoptionController.java b/src/main/java/org/example/petshopdesktop/controllers/AdoptionController.java index c60ddf83..611d88f1 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/AdoptionController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/AdoptionController.java @@ -1,5 +1,6 @@ package org.example.petshopdesktop.controllers; +import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.ActionEvent; @@ -10,15 +11,16 @@ import javafx.scene.control.*; import javafx.scene.control.cell.PropertyValueFactory; import javafx.stage.Modality; import javafx.stage.Stage; +import org.example.petshopdesktop.api.dto.adoption.AdoptionResponse; +import org.example.petshopdesktop.api.endpoints.AdoptionApi; import org.example.petshopdesktop.controllers.dialogcontrollers.AdoptionDialogController; -import org.example.petshopdesktop.database.AdoptionDB; import org.example.petshopdesktop.models.Adoption; import org.example.petshopdesktop.util.ActivityLogger; import java.io.IOException; -import java.sql.SQLException; -import java.sql.SQLIntegrityConstraintViolationException; +import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; public class AdoptionController { @@ -35,7 +37,7 @@ public class AdoptionController { private TableColumn colAdoptionId; @FXML - private TableColumn colPetId; + private TableColumn colPetId; @FXML private TableColumn colCustomerName; @@ -66,7 +68,7 @@ public class AdoptionController { tvAdoptions.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.MULTIPLE); colAdoptionId.setCellValueFactory(new PropertyValueFactory<>("adoptionId")); - colPetId.setCellValueFactory(new PropertyValueFactory<>("petId")); + colPetId.setCellValueFactory(new PropertyValueFactory<>("petName")); colCustomerName.setCellValueFactory(new PropertyValueFactory<>("customerName")); colAdoptionDate.setCellValueFactory(new PropertyValueFactory<>("adoptionDate")); colAdoptionFee.setCellValueFactory(new PropertyValueFactory<>("adoptionFee")); @@ -118,47 +120,24 @@ public class AdoptionController { //if confirmed, start deletion if (result.isPresent() && result.get() == ButtonType.OK) { - int successCount = 0; - int failCount = 0; - StringBuilder errors = new StringBuilder(); + List ids = selectedAdoptions.stream() + .map(a -> (long) a.getAdoptionId()) + .collect(Collectors.toList()); - for (Adoption adoption : selectedAdoptions) { - try { - int numRows = AdoptionDB.deleteAdoption(adoption.getAdoptionId()); - if (numRows > 0) { - successCount++; - } else { - failCount++; - } - } - catch (SQLIntegrityConstraintViolationException e) { - ActivityLogger.getInstance().logException( - "AdoptionController.btnDeleteClicked", - e, - String.format("Attempting to delete adoption ID %d - foreign key constraint", adoption.getAdoptionId())); - failCount++; - errors.append("Adoption ID ").append(adoption.getAdoptionId()).append(" is referenced in another table\n"); - } catch (SQLException e) { - ActivityLogger.getInstance().logException( - "AdoptionController.btnDeleteClicked", - e, - String.format("Attempting to delete adoption ID %d", adoption.getAdoptionId())); - failCount++; - errors.append("Failed to delete adoption ID ").append(adoption.getAdoptionId()).append("\n"); - } - } - - //show results - if (failCount > 0) { - Alert alert = new Alert(Alert.AlertType.WARNING); - alert.setHeaderText("Delete Operation Completed with Errors"); - alert.setContentText(String.format("Deleted: %d\nFailed: %d\n\n%s", - successCount, failCount, errors.toString())); - alert.showAndWait(); - } else if (successCount > 0) { + try { + AdoptionApi.getInstance().deleteAdoptions(ids); Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setHeaderText("Database Operation Confirmed"); - alert.setContentText("Successfully deleted " + successCount + " adoption record(s)"); + alert.setContentText("Successfully deleted " + ids.size() + " adoption record(s)"); + alert.showAndWait(); + } catch (Exception e) { + ActivityLogger.getInstance().logException( + "AdoptionController.btnDeleteClicked", + e, + "Deleting adoptions"); + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Delete Operation Failed"); + alert.setContentText(e.getMessage()); alert.showAndWait(); } @@ -181,35 +160,55 @@ public class AdoptionController { } private void displayFilteredAdoptions(String filter) { - data.clear(); - try { - if (txtSearch.getText() == null || txtSearch.getText().isEmpty()) { - displayAdoptions(); - } else { - data = AdoptionDB.getFilteredAdoptions(filter); - tvAdoptions.setItems(data); - } - } catch (Exception e) { - ActivityLogger.getInstance().logException( - "AdoptionController.displayFilteredAdoptions", - e, - "Filtering adoptions with filter: " + filter); - System.out.println("Error while fetching table data: " + e.getMessage()); + if (txtSearch.getText() == null || txtSearch.getText().isEmpty()) { + displayAdoptions(); + } else { + new Thread(() -> { + try { + List adoptions = AdoptionApi.getInstance().listAdoptions(filter); + List adoptionList = adoptions.stream() + .map(this::mapToAdoption) + .collect(Collectors.toList()); + + Platform.runLater(() -> { + data.setAll(adoptionList); + tvAdoptions.setItems(data); + }); + } catch (Exception e) { + Platform.runLater(() -> { + System.out.println("Error while fetching table data: " + e.getMessage()); + ActivityLogger.getInstance().logException( + "AdoptionController.displayFilteredAdoptions", + e, + "Filtering adoptions with filter: " + filter); + }); + } + }).start(); } } private void displayAdoptions() { - data.clear(); - try { - data = AdoptionDB.getAdoptions(); - } catch (SQLException e) { - ActivityLogger.getInstance().logException( - "AdoptionController.displayAdoptions", - e, - "Fetching adoption data for table display"); - System.out.println("Error while fetching table data: " + e.getMessage()); - } - tvAdoptions.setItems(data); + new Thread(() -> { + try { + List adoptions = AdoptionApi.getInstance().listAdoptions(null); + List adoptionList = adoptions.stream() + .map(this::mapToAdoption) + .collect(Collectors.toList()); + + Platform.runLater(() -> { + data.setAll(adoptionList); + tvAdoptions.setItems(data); + }); + } catch (Exception e) { + Platform.runLater(() -> { + System.out.println("Error while fetching table data: " + e.getMessage()); + ActivityLogger.getInstance().logException( + "AdoptionController.displayAdoptions", + e, + "Fetching adoption data for table display"); + }); + } + }).start(); } private void openDialog(Adoption adoption, String mode) { @@ -244,4 +243,17 @@ public class AdoptionController { btnEdit.setDisable(true); txtSearch.setText(""); } + + private Adoption mapToAdoption(AdoptionResponse response) { + return new Adoption( + response.getId().intValue(), + 0, + 0, + response.getPetName(), + response.getCustomerName(), + response.getAdoptionDate() != null ? response.getAdoptionDate().toString() : "", + 0.0, + response.getAdoptionStatus() + ); + } } diff --git a/src/main/java/org/example/petshopdesktop/controllers/AnalyticsController.java b/src/main/java/org/example/petshopdesktop/controllers/AnalyticsController.java index 6bb2a28a..b0637ab0 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/AnalyticsController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/AnalyticsController.java @@ -1,19 +1,25 @@ package org.example.petshopdesktop.controllers; -import javafx.collections.ObservableList; +import javafx.application.Platform; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.chart.*; import javafx.scene.control.Button; import javafx.scene.control.Label; -import org.example.petshopdesktop.auth.UserSession; -import org.example.petshopdesktop.database.SaleDB; -import org.example.petshopdesktop.models.analytics.*; +import org.example.petshopdesktop.api.dto.analytics.DailySales; +import org.example.petshopdesktop.api.dto.analytics.DashboardResponse; +import org.example.petshopdesktop.api.dto.analytics.TopProduct; +import org.example.petshopdesktop.api.dto.sale.SaleResponse; +import org.example.petshopdesktop.api.endpoints.AnalyticsApi; +import org.example.petshopdesktop.api.endpoints.SaleApi; import org.example.petshopdesktop.util.ActivityLogger; +import java.math.BigDecimal; +import java.math.RoundingMode; import java.text.NumberFormat; import java.time.format.DateTimeFormatter; -import java.util.Locale; +import java.util.*; +import java.util.stream.Collectors; public class AnalyticsController { @@ -78,79 +84,111 @@ public class AnalyticsController { private void loadAnalyticsData() { lblError.setVisible(false); - try { - loadSummaryData(); - loadSalesOverTime(); - loadTopProductsByRevenue(); - loadTopProductsByQuantity(); - loadPaymentMethodDistribution(); - loadEmployeePerformance(); - } catch (Exception e) { - ActivityLogger.getInstance().logException("AnalyticsController.loadAnalyticsData", e, "Loading analytics data"); - lblError.setText("Error loading analytics data. Please try again."); - lblError.setVisible(true); + new Thread(() -> { + try { + DashboardResponse dashboard = AnalyticsApi.getInstance().getDashboard(30, 10); + List sales = SaleApi.getInstance().listSales(0, Integer.MAX_VALUE, null); + + Platform.runLater(() -> { + try { + loadSummaryData(dashboard); + loadSalesOverTime(dashboard); + loadTopProductsByRevenue(dashboard); + loadTopProductsByQuantity(dashboard); + loadPaymentMethodDistribution(sales); + loadEmployeePerformance(sales); + } catch (Exception e) { + ActivityLogger.getInstance().logException("AnalyticsController.loadAnalyticsData", e, "Loading analytics data"); + lblError.setText("Error loading analytics data. Please try again."); + lblError.setVisible(true); + } + }); + } catch (Exception e) { + Platform.runLater(() -> { + ActivityLogger.getInstance().logException("AnalyticsController.loadAnalyticsData", e, "Loading analytics data"); + lblError.setText("Error loading analytics data. Please try again."); + lblError.setVisible(true); + }); + } + }).start(); + } + + private void loadSummaryData(DashboardResponse dashboard) throws Exception { + if (dashboard != null) { + BigDecimal totalRevenue = dashboard.getTotalRevenue() != null ? dashboard.getTotalRevenue() : BigDecimal.ZERO; + Long totalSales = dashboard.getTotalSales() != null ? dashboard.getTotalSales() : 0L; + Long totalProducts = dashboard.getTotalProducts() != null ? dashboard.getTotalProducts() : 0L; + + lblTotalRevenue.setText(currency.format(totalRevenue)); + lblTotalTransactions.setText(wholeNumber.format(totalSales)); + + BigDecimal avgTransaction = BigDecimal.ZERO; + if (totalSales > 0) { + avgTransaction = totalRevenue.divide(BigDecimal.valueOf(totalSales), 2, RoundingMode.HALF_UP); + } + lblAvgTransaction.setText(currency.format(avgTransaction)); + lblTotalItems.setText(wholeNumber.format(totalProducts)); } } - private void loadSummaryData() throws Exception { - SalesSummary summary = SaleDB.getSalesSummary(); - if (summary != null) { - lblTotalRevenue.setText(currency.format(summary.getTotalRevenue())); - lblTotalTransactions.setText(wholeNumber.format(summary.getTotalTransactions())); - lblAvgTransaction.setText(currency.format(summary.getAvgTransactionValue())); - lblTotalItems.setText(wholeNumber.format(summary.getTotalItemsSold())); - } - } - - private void loadSalesOverTime() throws Exception { - ObservableList data = SaleDB.getDailySalesRevenue(); + private void loadSalesOverTime(DashboardResponse dashboard) throws Exception { + List dailySales = dashboard.getDailySales() != null ? dashboard.getDailySales() : new ArrayList<>(); XYChart.Series series = new XYChart.Series<>(); series.setName("Daily Revenue"); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd"); - for (DailySalesData dailySale : data) { + for (DailySales dailySale : dailySales) { String dateStr = dailySale.getDate().format(formatter); - series.getData().add(new XYChart.Data<>(dateStr, dailySale.getRevenue())); + BigDecimal totalSales = dailySale.getTotalSales() != null ? dailySale.getTotalSales() : BigDecimal.ZERO; + series.getData().add(new XYChart.Data<>(dateStr, totalSales)); } chartSalesOverTime.getData().clear(); chartSalesOverTime.getData().add(series); } - private void loadTopProductsByRevenue() throws Exception { - ObservableList data = SaleDB.getTopProductsByRevenue(10); + private void loadTopProductsByRevenue(DashboardResponse dashboard) throws Exception { + List topProducts = dashboard.getTopProducts() != null ? dashboard.getTopProducts() : new ArrayList<>(); XYChart.Series series = new XYChart.Series<>(); series.setName("Revenue"); - for (ProductSalesData product : data) { - series.getData().add(new XYChart.Data<>(product.getTotalRevenue(), product.getProductName())); + for (TopProduct product : topProducts) { + BigDecimal totalRevenue = product.getTotalRevenue() != null ? product.getTotalRevenue() : BigDecimal.ZERO; + series.getData().add(new XYChart.Data<>(totalRevenue, product.getProductName())); } chartTopRevenue.getData().clear(); chartTopRevenue.getData().add(series); } - private void loadTopProductsByQuantity() throws Exception { - ObservableList data = SaleDB.getTopProductsByQuantity(10); + private void loadTopProductsByQuantity(DashboardResponse dashboard) throws Exception { + List topProducts = dashboard.getTopProducts() != null ? dashboard.getTopProducts() : new ArrayList<>(); XYChart.Series series = new XYChart.Series<>(); series.setName("Quantity"); - for (ProductSalesData product : data) { - series.getData().add(new XYChart.Data<>(product.getTotalQuantity(), product.getProductName())); + for (TopProduct product : topProducts) { + Integer quantitySold = product.getQuantitySold() != null ? product.getQuantitySold() : 0; + series.getData().add(new XYChart.Data<>(quantitySold, product.getProductName())); } chartTopQuantity.getData().clear(); chartTopQuantity.getData().add(series); } - private void loadPaymentMethodDistribution() throws Exception { - ObservableList data = SaleDB.getPaymentMethodDistribution(); + private void loadPaymentMethodDistribution(List sales) throws Exception { + Map paymentMethodCount = sales.stream() + .filter(sale -> sale.getIsRefund() == null || !sale.getIsRefund()) + .collect(Collectors.groupingBy( + sale -> sale.getPaymentMethod() != null ? sale.getPaymentMethod() : "Unknown", + Collectors.counting() + )); + chartPaymentMethods.getData().clear(); - for (PaymentMethodData payment : data) { + for (Map.Entry entry : paymentMethodCount.entrySet()) { PieChart.Data slice = new PieChart.Data( - payment.getPaymentMethod() + " (" + payment.getTransactionCount() + ")", - payment.getTransactionCount() + entry.getKey() + " (" + entry.getValue() + ")", + entry.getValue() ); chartPaymentMethods.getData().add(slice); } diff --git a/src/main/java/org/example/petshopdesktop/controllers/AppointmentController.java b/src/main/java/org/example/petshopdesktop/controllers/AppointmentController.java index ac1a2c35..430804ae 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/AppointmentController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/AppointmentController.java @@ -1,5 +1,6 @@ package org.example.petshopdesktop.controllers; +import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.collections.transformation.FilteredList; @@ -13,10 +14,14 @@ import javafx.stage.Modality; import javafx.stage.Stage; import org.example.petshopdesktop.DTOs.AppointmentDTO; +import org.example.petshopdesktop.api.dto.appointment.AppointmentResponse; +import org.example.petshopdesktop.api.endpoints.AppointmentApi; import org.example.petshopdesktop.controllers.dialogcontrollers.AppointmentDialogController; -import org.example.petshopdesktop.database.AppointmentDB; import org.example.petshopdesktop.util.ActivityLogger; +import java.util.List; +import java.util.stream.Collectors; + public class AppointmentController { @FXML private TableView tvAppointments; @@ -71,41 +76,50 @@ public class AppointmentController { } private void loadAppointments(){ - try{ - appointments.setAll(AppointmentDB.getAppointmentDTOs()); - }catch(Exception e){ - ActivityLogger.getInstance().logException( - "AppointmentController.loadAppointments", - e, - "Loading appointments for table display"); - e.printStackTrace(); - } + new Thread(() -> { + try{ + List responses = AppointmentApi.getInstance().listAppointments(null); + List appointmentDTOs = responses.stream() + .map(this::mapToAppointmentDTO) + .collect(Collectors.toList()); + + Platform.runLater(() -> { + appointments.setAll(appointmentDTOs); + }); + }catch(Exception e){ + Platform.runLater(() -> { + ActivityLogger.getInstance().logException( + "AppointmentController.loadAppointments", + e, + "Loading appointments for table display"); + e.printStackTrace(); + }); + } + }).start(); } private void applyFilter(String text) { - if (filtered == null) { - return; - } + String query = text == null || text.trim().isEmpty() ? null : text.trim(); + new Thread(() -> { + try { + List responses = AppointmentApi.getInstance().listAppointments(query); + List appointmentDTOs = responses.stream() + .map(this::mapToAppointmentDTO) + .collect(Collectors.toList()); - String q = text == null ? "" : text.trim().toLowerCase(); - if (q.isEmpty()) { - filtered.setPredicate(a -> true); - return; - } - - filtered.setPredicate(a -> - String.valueOf(a.getAppointmentId()).contains(q) - || safe(a.getPetName()).contains(q) - || safe(a.getServiceName()).contains(q) - || safe(a.getAppointmentDate()).contains(q) - || safe(a.getAppointmentTime()).contains(q) - || safe(a.getCustomerName()).contains(q) - || safe(a.getAppointmentStatus()).contains(q) - ); - } - - private static String safe(String v) { - return v == null ? "" : v.toLowerCase(); + Platform.runLater(() -> { + appointments.setAll(appointmentDTOs); + }); + } catch (Exception e) { + Platform.runLater(() -> { + ActivityLogger.getInstance().logException( + "AppointmentController.applyFilter", + e, + String.format("Filtering appointments with query: %s", query)); + e.printStackTrace(); + }); + } + }).start(); } @FXML @@ -145,35 +159,24 @@ public class AppointmentController { //if confirmed, start deletion if (result.isPresent() && result.get() == ButtonType.OK) { - int successCount = 0; - int failCount = 0; - StringBuilder errors = new StringBuilder(); + List ids = selectedAppointments.stream() + .map(a -> (long) a.getAppointmentId()) + .collect(Collectors.toList()); - for (AppointmentDTO appointment : selectedAppointments) { - try{ - AppointmentDB.deleteAppointment(appointment.getAppointmentId()); - successCount++; - }catch(Exception e){ - ActivityLogger.getInstance().logException( - "AppointmentController.btnDeleteClicked", - e, - String.format("Attempting to delete appointment ID %d", appointment.getAppointmentId())); - failCount++; - errors.append("Failed to delete appointment ID ").append(appointment.getAppointmentId()).append("\n"); - } - } - - //show results - if (failCount > 0) { - Alert alert = new Alert(Alert.AlertType.WARNING); - alert.setHeaderText("Delete Operation Completed with Errors"); - alert.setContentText(String.format("Deleted: %d\nFailed: %d\n\n%s", - successCount, failCount, errors.toString())); - alert.showAndWait(); - } else if (successCount > 0) { + try { + AppointmentApi.getInstance().deleteAppointments(ids); Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setHeaderText("Database Operation Confirmed"); - alert.setContentText("Successfully deleted " + successCount + " appointment(s)"); + alert.setContentText("Successfully deleted " + ids.size() + " appointment(s)"); + alert.showAndWait(); + } catch (Exception e) { + ActivityLogger.getInstance().logException( + "AppointmentController.btnDeleteClicked", + e, + "Deleting appointments"); + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Delete Operation Failed"); + alert.setContentText(e.getMessage()); alert.showAndWait(); } @@ -225,4 +228,19 @@ public class AppointmentController { alert.setContentText(msg); alert.showAndWait(); } + + private AppointmentDTO mapToAppointmentDTO(AppointmentResponse response) { + return new AppointmentDTO( + response.getId().intValue(), + 0, + response.getCustomerName(), + 0, + response.getPetNames(), + 0, + response.getServiceName(), + response.getAppointmentDate().toString(), + response.getAppointmentTime().toString(), + response.getAppointmentStatus() + ); + } } diff --git a/src/main/java/org/example/petshopdesktop/controllers/InventoryController.java b/src/main/java/org/example/petshopdesktop/controllers/InventoryController.java index 3a7d9bcd..2dc87162 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/InventoryController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/InventoryController.java @@ -1,5 +1,6 @@ package org.example.petshopdesktop.controllers; +import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.ActionEvent; @@ -10,15 +11,16 @@ import javafx.scene.control.*; import javafx.scene.control.cell.PropertyValueFactory; import javafx.stage.Modality; import javafx.stage.Stage; +import org.example.petshopdesktop.api.dto.inventory.InventoryResponse; +import org.example.petshopdesktop.api.endpoints.InventoryApi; import org.example.petshopdesktop.controllers.dialogcontrollers.InventoryDialogController; -import org.example.petshopdesktop.database.InventoryDB; import org.example.petshopdesktop.models.Inventory; import org.example.petshopdesktop.util.ActivityLogger; import java.io.IOException; -import java.sql.SQLException; -import java.sql.SQLIntegrityConstraintViolationException; +import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; public class InventoryController { @@ -58,11 +60,9 @@ public class InventoryController { //Loads upon view bootup @FXML void initialize() { - //Buttons disabled until row is selected btnEdit.setDisable(true); btnDelete.setDisable(true); - //Enable multiple selection - tvInventory.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.MULTIPLE); + tvInventory.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.SINGLE); colInventoryId.setCellValueFactory(new PropertyValueFactory<>("inventoryId")); colProductId.setCellValueFactory(new PropertyValueFactory<>("prodId")); @@ -71,19 +71,16 @@ public class InventoryController { displayInventory(); - //Enables buttons when row is selected tvInventory.getSelectionModel().selectedItemProperty().addListener( (observable, oldValue, newValue) -> { btnEdit.setDisable(false); btnDelete.setDisable(false); }); - //Filter as user types txtSearch.textProperty().addListener((observable, oldValue, newValue) -> { displayFilteredInventory(newValue); }); - //EventListener for DELETE key tvInventory.setOnKeyPressed(event -> { if (event.getCode() == javafx.scene.input.KeyCode.DELETE) { if (tvInventory.getSelectionModel().getSelectedItem() != null) { @@ -100,71 +97,35 @@ public class InventoryController { openDialog(null, mode); } - //Prompts user for confirmation prior to deletion @FXML void btnDeleteClicked(ActionEvent event) { - //get selected inventory records - var selectedInventory = tvInventory.getSelectionModel().getSelectedItems(); - if (selectedInventory.isEmpty()) return; + Inventory selectedInventory = tvInventory.getSelectionModel().getSelectedItem(); + if (selectedInventory == null) return; - //ask user to confirm Alert question = new Alert(Alert.AlertType.CONFIRMATION); question.setHeaderText("Please confirm delete"); - String message = selectedInventory.size() == 1 - ? "Are you sure you want to delete this inventory record?" - : "Are you sure you want to delete " + selectedInventory.size() + " inventory records?"; - question.setContentText(message); + question.setContentText("Are you sure you want to delete this inventory record?"); question.getDialogPane().lookupButton(ButtonType.OK).requestFocus(); Optional result = question.showAndWait(); - //if confirmed, start deletion if (result.isPresent() && result.get() == ButtonType.OK) { - int successCount = 0; - int failCount = 0; - StringBuilder errors = new StringBuilder(); - - for (Inventory inventory : selectedInventory) { - try { - int numRows = InventoryDB.deleteInventory(inventory.getInventoryId()); - if (numRows > 0) { - successCount++; - } else { - failCount++; - } - } - catch (SQLIntegrityConstraintViolationException e) { - ActivityLogger.getInstance().logException( - "InventoryController.btnDeleteClicked", - e, - String.format("Attempting to delete inventory ID %d - foreign key constraint", inventory.getInventoryId())); - failCount++; - errors.append("Inventory record '").append(inventory.getProdName()).append("' is referenced in another table\n"); - } - catch (SQLException e) { - ActivityLogger.getInstance().logException( - "InventoryController.btnDeleteClicked", - e, - String.format("Attempting to delete inventory ID %d", inventory.getInventoryId())); - failCount++; - errors.append("Failed to delete '").append(inventory.getProdName()).append("'\n"); - } - } - - //show results - if (failCount > 0) { - Alert alert = new Alert(Alert.AlertType.WARNING); - alert.setHeaderText("Delete Operation Completed with Errors"); - alert.setContentText(String.format("Deleted: %d\nFailed: %d\n\n%s", - successCount, failCount, errors.toString())); - alert.showAndWait(); - } else if (successCount > 0) { + try { + InventoryApi.getInstance().deleteInventory((long) selectedInventory.getInventoryId()); Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setHeaderText("Database Operation Confirmed"); - alert.setContentText("Successfully deleted " + successCount + " inventory record(s)"); + alert.setContentText("Successfully deleted inventory record"); + alert.showAndWait(); + } catch (Exception e) { + ActivityLogger.getInstance().logException( + "InventoryController.btnDeleteClicked", + e, + "Deleting inventory"); + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Delete Operation Failed"); + alert.setContentText(e.getMessage()); alert.showAndWait(); } - //refresh display and reset inputs displayInventory(); btnDelete.setDisable(true); btnEdit.setDisable(true); @@ -183,66 +144,72 @@ public class InventoryController { } } - //Search filter private void displayFilteredInventory(String filter) { - data.clear(); - try { - //If search box is empty, display all inventory - if (txtSearch.getText() == null || txtSearch.getText().isEmpty()) { - displayInventory(); - } + if (txtSearch.getText() == null || txtSearch.getText().isEmpty()) { + displayInventory(); + } else { + new Thread(() -> { + try { + List inventories = InventoryApi.getInstance().listInventory(filter); + List inventoryList = inventories.stream() + .map(this::mapToInventory) + .collect(Collectors.toList()); - else { - data = InventoryDB.getFilteredInventory(filter); - tvInventory.setItems(data); - } - } - - catch (Exception e) { - ActivityLogger.getInstance().logException( - "InventoryController.displayFilteredInventory", - e, - "Filtering inventory with filter: " + filter); - System.out.println("Error while fetching table data: " + e.getMessage()); + Platform.runLater(() -> { + data.setAll(inventoryList); + tvInventory.setItems(data); + }); + } catch (Exception e) { + Platform.runLater(() -> { + System.out.println("Error while fetching table data: " + e.getMessage()); + ActivityLogger.getInstance().logException( + "InventoryController.displayFilteredInventory", + e, + String.format("Filtering inventory with keyword: %s", filter)); + }); + } + }).start(); } } - //Displays all records from DB private void displayInventory() { - data.clear(); - try { - data = InventoryDB.getInventory(); - } + new Thread(() -> { + try { + List inventories = InventoryApi.getInstance().listInventory(null); + List inventoryList = inventories.stream() + .map(this::mapToInventory) + .collect(Collectors.toList()); - catch (SQLException e) { - ActivityLogger.getInstance().logException( - "InventoryController.displayInventory", - e, - "Fetching inventory data for table display"); - System.out.println("Error while fetching table data: " + e.getMessage()); - } - tvInventory.setItems(data); + Platform.runLater(() -> { + data.setAll(inventoryList); + tvInventory.setItems(data); + }); + } catch (Exception e) { + Platform.runLater(() -> { + System.out.println("Error while fetching table data: " + e.getMessage()); + ActivityLogger.getInstance().logException( + "InventoryController.displayInventory", + e, + "Fetching inventory data for table display"); + }); + } + }).start(); } - //Opens inventory-dialog-view private void openDialog(Inventory inventory, String mode) { - //Opens FXML FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/inventory-dialog-view.fxml")); Scene scene = null; try { scene = new Scene(fxmlLoader.load()); - } - - catch (IOException e) { + } catch (IOException e) { ActivityLogger.getInstance().logException( "InventoryController.openDialog", e, - "Loading inventory dialog in " + mode + " mode"); + String.format("Loading inventory dialog view in %s mode", mode)); throw new RuntimeException(e); } - //Passes data and mode to the view InventoryDialogController dialogController = fxmlLoader.getController(); dialogController.setMode(mode); @@ -256,10 +223,22 @@ public class InventoryController { dialogStage.setScene(scene); dialogStage.showAndWait(); - //Refresh inventory displayInventory(); btnDelete.setDisable(true); btnEdit.setDisable(true); txtSearch.setText(""); } + + private Inventory mapToInventory(InventoryResponse response) { + return new Inventory( + response.getId().intValue(), + 0, + response.getProductName(), + response.getCategoryName() != null ? response.getCategoryName() : "", + 0, + response.getStoreName() != null ? response.getStoreName() : "", + response.getStockQuantity() != null ? response.getStockQuantity() : 0, + response.getReorderLevel() != null ? response.getReorderLevel() : 0 + ); + } } diff --git a/src/main/java/org/example/petshopdesktop/controllers/ProductSupplierController.java b/src/main/java/org/example/petshopdesktop/controllers/ProductSupplierController.java index ff5b3009..e3e50d09 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/ProductSupplierController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/ProductSupplierController.java @@ -1,5 +1,6 @@ package org.example.petshopdesktop.controllers; +import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.ActionEvent; @@ -10,19 +11,16 @@ import javafx.scene.control.*; import javafx.scene.control.cell.PropertyValueFactory; import javafx.stage.Modality; import javafx.stage.Stage; -import org.example.petshopdesktop.DTOs.ProductDTO; import org.example.petshopdesktop.DTOs.ProductSupplierDTO; -import org.example.petshopdesktop.controllers.dialogcontrollers.ProductDialogController; +import org.example.petshopdesktop.api.dto.productsupplier.ProductSupplierResponse; +import org.example.petshopdesktop.api.endpoints.ProductSupplierApi; import org.example.petshopdesktop.controllers.dialogcontrollers.ProductSupplierDialogController; -import org.example.petshopdesktop.database.ProductDB; -import org.example.petshopdesktop.database.ProductSupplierDB; -import org.example.petshopdesktop.models.ProductSupplier; import org.example.petshopdesktop.util.ActivityLogger; import java.io.IOException; -import java.sql.SQLException; -import java.sql.SQLIntegrityConstraintViolationException; +import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; public class ProductSupplierController { @@ -107,22 +105,27 @@ public class ProductSupplierController { * Display the ProductSupplierDTO to table view */ private void displayProductSupplier() { - //Erase old content - data.clear(); + new Thread(() -> { + try { + List productSuppliers = ProductSupplierApi.getInstance().listProductSuppliers(null); + List productSupplierDTOs = productSuppliers.stream() + .map(this::mapToProductSupplierDTO) + .collect(Collectors.toList()); - //get ProductSupplier from database - try{ - data = ProductSupplierDB.getProductSupplierDTO(); - } catch (SQLException e) { - ActivityLogger.getInstance().logException( - "ProductSupplierController.displayProductSupplier", - e, - "Fetching product-supplier data for table display"); - System.out.println("Error while fetching table data: " + e.getMessage()); - } - - //put data in the table - tvProductSuppliers.setItems(data); + Platform.runLater(() -> { + data.setAll(productSupplierDTOs); + tvProductSuppliers.setItems(data); + }); + } catch (Exception e) { + Platform.runLater(() -> { + System.out.println("Error while fetching table data: " + e.getMessage()); + ActivityLogger.getInstance().logException( + "ProductSupplierController.displayProductSupplier", + e, + "Fetching product-supplier data for table display"); + }); + } + }).start(); } /** @@ -130,22 +133,30 @@ public class ProductSupplierController { * @param filter word to filter table */ private void displayFilteredProductSupplier(String filter){ - data.clear(); - try{ - if (txtSearch.getText() == null || txtSearch.getText().isEmpty()){ - displayProductSupplier(); //If search bar is empty just display everything - } - else{ - //Filter the using the keyword - data = ProductSupplierDB.getFilteredProductSupplierDTO(filter); - tvProductSuppliers.setItems(data); - } - } catch (Exception e) { - ActivityLogger.getInstance().logException( - "ProductSupplierController.displayFilteredProductSupplier", - e, - "Filtering product-supplier data with filter: " + filter); - System.out.println("Error while fetching table data: " + e.getMessage()); + if (txtSearch.getText() == null || txtSearch.getText().isEmpty()){ + displayProductSupplier(); + } else { + new Thread(() -> { + try { + List productSuppliers = ProductSupplierApi.getInstance().listProductSuppliers(filter); + List productSupplierDTOs = productSuppliers.stream() + .map(this::mapToProductSupplierDTO) + .collect(Collectors.toList()); + + Platform.runLater(() -> { + data.setAll(productSupplierDTOs); + tvProductSuppliers.setItems(data); + }); + } catch (Exception e) { + Platform.runLater(() -> { + System.out.println("Error while fetching table data: " + e.getMessage()); + ActivityLogger.getInstance().logException( + "ProductSupplierController.displayFilteredProductSupplier", + e, + "Filtering product-supplier data with filter: " + filter); + }); + } + }).start(); } } @@ -181,52 +192,24 @@ public class ProductSupplierController { //if confirmed, start deletion if (result.isPresent() && result.get() == ButtonType.OK) { - int successCount = 0; - int failCount = 0; - StringBuilder errors = new StringBuilder(); + List ids = selectedProductSuppliers.stream() + .map(ps -> (long) ps.getSupId()) + .collect(Collectors.toList()); - for (ProductSupplierDTO productSupplier : selectedProductSuppliers) { - try{ - int numRows = ProductSupplierDB.deleteProductSupplier(productSupplier.getSupId(), productSupplier.getProdId()); - if (numRows > 0) { - successCount++; - } else { - failCount++; - } - } - catch (SQLIntegrityConstraintViolationException e){ - ActivityLogger.getInstance().logException( - "ProductSupplierController.btnDeleteClicked", - e, - String.format("Attempting to delete product-supplier - SupID: %d, ProdID: %d - foreign key constraint", - productSupplier.getSupId(), productSupplier.getProdId())); - failCount++; - errors.append(String.format("Product-Supplier '%s - %s' is referenced in another table\n", - productSupplier.getProdName(), productSupplier.getSupCompany())); - } - catch (SQLException e) { - ActivityLogger.getInstance().logException( - "ProductSupplierController.btnDeleteClicked", - e, - String.format("Attempting to delete product-supplier - SupID: %d, ProdID: %d", - productSupplier.getSupId(), productSupplier.getProdId())); - failCount++; - errors.append(String.format("Failed to delete '%s - %s'\n", - productSupplier.getProdName(), productSupplier.getSupCompany())); - } - } - - //show results - if (failCount > 0) { - Alert alert = new Alert(Alert.AlertType.WARNING); - alert.setHeaderText("Delete Operation Completed with Errors"); - alert.setContentText(String.format("Deleted: %d\nFailed: %d\n\n%s", - successCount, failCount, errors.toString())); - alert.showAndWait(); - } else if (successCount > 0) { + try { + ProductSupplierApi.getInstance().deleteProductSuppliers(ids); Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setHeaderText("Database Operation Confirmed"); - alert.setContentText("Successfully deleted " + successCount + " product-supplier(s)"); + alert.setContentText("Successfully deleted " + ids.size() + " product-supplier(s)"); + alert.showAndWait(); + } catch (Exception e) { + ActivityLogger.getInstance().logException( + "ProductSupplierController.btnDeleteClicked", + e, + "Deleting product-suppliers"); + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Delete Operation Failed"); + alert.setContentText(e.getMessage()); alert.showAndWait(); } @@ -297,4 +280,14 @@ public class ProductSupplierController { txtSearch.setText(""); } + private ProductSupplierDTO mapToProductSupplierDTO(ProductSupplierResponse response) { + return new ProductSupplierDTO( + response.getSupplierId().intValue(), + response.getProductId().intValue(), + response.getSupplierName(), + response.getProductName(), + response.getSupplierPrice().doubleValue() + ); + } + } diff --git a/src/main/java/org/example/petshopdesktop/controllers/PurchaseOrderController.java b/src/main/java/org/example/petshopdesktop/controllers/PurchaseOrderController.java index 58082dee..c0caeff9 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/PurchaseOrderController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/PurchaseOrderController.java @@ -1,5 +1,6 @@ package org.example.petshopdesktop.controllers; +import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.collections.transformation.FilteredList; @@ -7,9 +8,13 @@ import javafx.fxml.FXML; import javafx.scene.control.*; import javafx.scene.control.cell.PropertyValueFactory; import org.example.petshopdesktop.DTOs.PurchaseOrderDTO; -import org.example.petshopdesktop.database.PurchaseOrderDB; +import org.example.petshopdesktop.api.dto.purchaseorder.PurchaseOrderResponse; +import org.example.petshopdesktop.api.endpoints.PurchaseOrderApi; import org.example.petshopdesktop.util.ActivityLogger; +import java.util.List; +import java.util.stream.Collectors; + public class PurchaseOrderController { @FXML private Button btnRefresh; @@ -19,7 +24,7 @@ public class PurchaseOrderController { @FXML private TableView tvPurchaseOrders; - @FXML private TableColumn colOrderId; + @FXML private TableColumn colOrderId; @FXML private TableColumn colSupplier; @FXML private TableColumn colOrderDate; @FXML private TableColumn colStatus; @@ -53,17 +58,28 @@ public class PurchaseOrderController { } private void loadPurchaseOrders() { - try { - purchaseOrders.setAll(PurchaseOrderDB.getPurchaseOrders()); - } catch (Exception e) { - ActivityLogger.getInstance().logException( - "PurchaseOrderController.loadPurchaseOrders", - e, - "Loading purchase orders for table display"); - e.printStackTrace(); - new Alert(Alert.AlertType.ERROR, - "Unable to load purchase orders").showAndWait(); - } + new Thread(() -> { + try { + List responses = PurchaseOrderApi.getInstance().listPurchaseOrders(null); + List dtos = responses.stream() + .map(this::mapToPurchaseOrderDTO) + .collect(Collectors.toList()); + + Platform.runLater(() -> { + purchaseOrders.setAll(dtos); + tvPurchaseOrders.setItems(filtered); + }); + } catch (Exception e) { + Platform.runLater(() -> { + ActivityLogger.getInstance().logException( + "PurchaseOrderController.loadPurchaseOrders", + e, + "Loading purchase orders for table display"); + new Alert(Alert.AlertType.ERROR, + "Unable to load purchase orders").showAndWait(); + }); + } + }).start(); } private void applyFilter(String text) { @@ -93,4 +109,13 @@ public class PurchaseOrderController { void btnRefresh() { loadPurchaseOrders(); } + + private PurchaseOrderDTO mapToPurchaseOrderDTO(PurchaseOrderResponse response) { + return new PurchaseOrderDTO( + response.getId(), + response.getSupplierName(), + response.getOrderDate() != null ? response.getOrderDate().toString() : "", + response.getOrderStatus() + ); + } } \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/controllers/SaleController.java b/src/main/java/org/example/petshopdesktop/controllers/SaleController.java index 4d17a0b2..0e2041a2 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/SaleController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/SaleController.java @@ -22,20 +22,25 @@ import javafx.scene.layout.VBox; import javafx.stage.Modality; import javafx.stage.Stage; import org.example.petshopdesktop.auth.UserSession; -import org.example.petshopdesktop.database.InventoryDB; -import org.example.petshopdesktop.database.ProductDB; -import org.example.petshopdesktop.database.SaleDB; -import org.example.petshopdesktop.models.Inventory; +import javafx.concurrent.Task; +import org.example.petshopdesktop.api.endpoints.ProductApi; +import org.example.petshopdesktop.api.endpoints.SaleApi; +import org.example.petshopdesktop.api.dto.product.ProductResponse; +import org.example.petshopdesktop.api.dto.sale.SaleItemRequest; +import org.example.petshopdesktop.api.dto.sale.SaleItemResponse; +import org.example.petshopdesktop.api.dto.sale.SaleRequest; +import org.example.petshopdesktop.api.dto.sale.SaleResponse; import org.example.petshopdesktop.models.Product; import org.example.petshopdesktop.models.SaleCartItem; import org.example.petshopdesktop.models.SaleLineItem; import org.example.petshopdesktop.util.ActivityLogger; -import java.sql.SQLException; +import java.math.BigDecimal; import java.text.NumberFormat; -import java.util.HashMap; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; -import java.util.Map; public class SaleController { @@ -124,8 +129,8 @@ public class SaleController { private final ObservableList saleItems = FXCollections.observableArrayList(); private FilteredList filteredSales; - private final Map inventoryByProdId = new HashMap<>(); private final NumberFormat currency = NumberFormat.getCurrencyInstance(Locale.CANADA); + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); @FXML public void initialize() { @@ -133,7 +138,6 @@ public class SaleController { setupCreateSale(); applyRoleMode(); - refreshInventory(); refreshSales(); } @@ -170,11 +174,20 @@ public class SaleController { updateCartTotal(); try { - cbProduct.setItems(ProductDB.getProducts()); - } catch (SQLException e) { + List productResponses = ProductApi.getInstance().listProducts(null); + ObservableList products = FXCollections.observableArrayList(); + for (ProductResponse pr : productResponses) { + products.add(new Product( + pr.getId().intValue(), + pr.getProductName(), + pr.getPrice().doubleValue(), + 0, + pr.getDescription() + )); + } + cbProduct.setItems(products); + } catch (Exception e) { ActivityLogger.getInstance().logException("SaleController.setupCreateSale", e, "Loading products"); - } catch (RuntimeException e) { - ActivityLogger.getInstance().logException("SaleController.setupCreateSale", e, "Database connection"); } } @@ -185,42 +198,59 @@ public class SaleController { lblModeNote.setText(isAdmin ? "(View only)" : "(Staff can create sales)"); } - private void refreshInventory() { - inventoryByProdId.clear(); - try { - for (Inventory inv : InventoryDB.getInventory()) { - inventoryByProdId.put(inv.getProdId(), inv.getQuantity()); - } - } catch (SQLException e) { - ActivityLogger.getInstance().logException("SaleController.refreshInventory", e, "Loading inventory"); - } catch (RuntimeException e) { - ActivityLogger.getInstance().logException("SaleController.refreshInventory", e, "Database connection"); - } - } - private void refreshSales() { refreshSales(false); } private void refreshSales(boolean showErrorDialog) { - try { - saleItems.setAll(SaleDB.getSaleLineItems()); - } catch (SQLException e) { + Task> task = new Task>() { + @Override + protected List call() throws Exception { + List sales = SaleApi.getInstance().listSales(0, 1000, null); + List lineItems = new ArrayList<>(); + + for (SaleResponse sale : sales) { + String saleDate = sale.getSaleDate() != null + ? sale.getSaleDate().format(DATE_FORMATTER) + : ""; + + if (sale.getItems() != null && !sale.getItems().isEmpty()) { + for (SaleItemResponse item : sale.getItems()) { + lineItems.add(new SaleLineItem( + sale.getId().intValue(), + saleDate, + sale.getEmployeeName(), + item.getProductName(), + item.getQuantity(), + item.getUnitPrice().doubleValue(), + item.getLineTotal().doubleValue(), + sale.getPaymentMethod(), + sale.getIsRefund() != null && sale.getIsRefund() + )); + } + } + } + return lineItems; + } + }; + + task.setOnSucceeded(event -> { + saleItems.setAll(task.getValue()); + }); + + task.setOnFailed(event -> { + Throwable e = task.getException(); ActivityLogger.getInstance().logException("SaleController.refreshSales", e, "Loading sales"); if (showErrorDialog) { - showError("Sales", "Could not load sales."); + showError("Sales", "Could not load sales: " + e.getMessage()); } - } catch (RuntimeException e) { - ActivityLogger.getInstance().logException("SaleController.refreshSales", e, "Database connection"); - if (showErrorDialog) { - showError("Sales", "Database is not connected."); - } - } + }); + + new Thread(task).start(); } @FXML void btnRefresh(ActionEvent event) { - refreshInventory(); refreshSales(true); } @@ -244,18 +274,6 @@ public class SaleController { return; } - int stock = inventoryByProdId.getOrDefault(product.getProdId(), 0); - int alreadyInCart = cartItems.stream() - .filter(i -> i.getProdId() == product.getProdId()) - .mapToInt(SaleCartItem::getQuantity) - .sum(); - - int available = stock - alreadyInCart; - if (requestedQty > available) { - showError("Create Sale", "Not enough stock. Available: " + Math.max(0, available)); - return; - } - for (SaleCartItem item : cartItems) { if (item.getProdId() == product.getProdId()) { item.setQuantity(item.getQuantity() + requestedQty); @@ -291,9 +309,9 @@ public class SaleController { return; } - Integer employeeId = UserSession.getInstance().getEmployeeId(); - if (employeeId == null || employeeId <= 0) { - showError("Create Sale", "Employee is not set for this account."); + Long storeId = UserSession.getInstance().getStoreId(); + if (storeId == null || storeId <= 0) { + showError("Create Sale", "Store is not set for this account."); return; } @@ -309,20 +327,35 @@ public class SaleController { } try { - int saleId = SaleDB.createSale(employeeId, payment, cartItems); - showInfo("Sale saved", "Sale ID " + saleId + " was created."); + SaleRequest request = new SaleRequest(); + request.setStoreId(storeId); + request.setPaymentMethod(payment); + + List itemRequests = new ArrayList<>(); + for (SaleCartItem cartItem : cartItems) { + SaleItemRequest itemRequest = new SaleItemRequest(); + itemRequest.setProductId((long) cartItem.getProdId()); + itemRequest.setQuantity(cartItem.getQuantity()); + itemRequest.setUnitPrice(BigDecimal.valueOf(cartItem.getUnitPrice())); + itemRequests.add(itemRequest); + } + request.setItems(itemRequests); + + SaleResponse response = SaleApi.getInstance().createSale(request); + showInfo("Sale saved", "Sale ID " + response.getId() + " was created."); cartItems.clear(); updateCartTotal(); - refreshInventory(); refreshSales(true); - } catch (SQLException e) { + } catch (Exception e) { ActivityLogger.getInstance().logException("SaleController.btnSaveSale", e, "Creating sale"); - showError("Create Sale", e.getMessage() == null ? "Could not save the sale." : e.getMessage()); - } catch (RuntimeException e) { - ActivityLogger.getInstance().logException("SaleController.btnSaveSale", e, "Database connection"); - showError("Create Sale", "Database is not connected."); + String errorMsg = e.getMessage(); + if (errorMsg != null && errorMsg.contains("Insufficient inventory")) { + showError("Create Sale", "Insufficient stock for one or more items."); + } else { + showError("Create Sale", errorMsg != null ? errorMsg : "Could not save the sale."); + } } } diff --git a/src/main/java/org/example/petshopdesktop/controllers/ServiceController.java b/src/main/java/org/example/petshopdesktop/controllers/ServiceController.java index 2f5ae849..493d893b 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/ServiceController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/ServiceController.java @@ -1,8 +1,8 @@ package org.example.petshopdesktop.controllers; +import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; -import javafx.collections.transformation.FilteredList; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; @@ -10,12 +10,17 @@ import javafx.scene.Scene; import javafx.scene.control.*; import javafx.scene.control.cell.PropertyValueFactory; import javafx.stage.Stage; -import org.example.petshopdesktop.database.ServiceDB; -import org.example.petshopdesktop.models.Service; +import org.example.petshopdesktop.DTOs.ServiceDTO; +import org.example.petshopdesktop.api.dto.service.ServiceResponse; +import org.example.petshopdesktop.api.endpoints.ServiceApi; import org.example.petshopdesktop.controllers.dialogcontrollers.ServiceDialogController; import org.example.petshopdesktop.util.ActivityLogger; import javafx.stage.Modality; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + public class ServiceController { @@ -23,22 +28,23 @@ public class ServiceController { @FXML private Button btnDelete; @FXML private Button btnEdit; - @FXML private TableColumn colServiceId; - @FXML private TableColumn colServiceName; - @FXML private TableColumn colServiceDesc; - @FXML private TableColumn colServiceDuration; - @FXML private TableColumn colServicePrice; + @FXML private TableColumn colServiceId; + @FXML private TableColumn colServiceName; + @FXML private TableColumn colServiceDesc; + @FXML private TableColumn colServiceDuration; + @FXML private TableColumn colServicePrice; - @FXML private TableView tvServices; + @FXML private TableView tvServices; @FXML private TextField txtSearch; - private final ObservableList services = FXCollections.observableArrayList(); - private FilteredList filtered; + private ObservableList data = FXCollections.observableArrayList(); + private String mode = null; @FXML public void initialize() { - //Enable multiple selection + btnEdit.setDisable(true); + btnDelete.setDisable(true); tvServices.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.MULTIPLE); colServiceId.setCellValueFactory(new PropertyValueFactory<>("serviceId")); @@ -47,14 +53,19 @@ public class ServiceController { colServiceDuration.setCellValueFactory(new PropertyValueFactory<>("serviceDuration")); colServicePrice.setCellValueFactory(new PropertyValueFactory<>("servicePrice")); - filtered = new FilteredList<>(services, s -> true); - tvServices.setItems(filtered); + displayServices(); - if (txtSearch != null) { - txtSearch.textProperty().addListener((obs, o, n) -> applyFilter(n)); - } + tvServices.getSelectionModel().selectedItemProperty().addListener( + (observable, oldValue, newValue) -> { + btnEdit.setDisable(false); + btnDelete.setDisable(false); + } + ); + + txtSearch.textProperty().addListener((observable, oldValue, newValue) -> { + displayFilteredServices(newValue); + }); - //EventListener for DELETE key tvServices.setOnKeyPressed(event -> { if (event.getCode() == javafx.scene.input.KeyCode.DELETE) { if (tvServices.getSelectionModel().getSelectedItem() != null) { @@ -62,75 +73,82 @@ public class ServiceController { } } }); - - loadServices(); } - private void loadServices() { - try { - services.setAll(ServiceDB.getServices()); - } catch (Exception e) { - ActivityLogger.getInstance().logException( - "ServiceController.loadServices", - e, - "Loading services for table display"); - showAlert("Database Error", "Unable to load services."); - e.printStackTrace(); - } + private void displayServices() { + new Thread(() -> { + try { + List services = ServiceApi.getInstance().listServices(null); + List serviceDTOs = services.stream() + .map(this::mapToServiceDTO) + .collect(Collectors.toList()); + + Platform.runLater(() -> { + data.setAll(serviceDTOs); + tvServices.setItems(data); + }); + } catch (Exception e) { + Platform.runLater(() -> { + System.out.println("Error while fetching table data: " + e.getMessage()); + ActivityLogger.getInstance().logException( + "ServiceController.displayServices", + e, + "Fetching service data for table display"); + }); + } + }).start(); } - private void applyFilter(String text) { - if (filtered == null) { - return; + private void displayFilteredServices(String filter) { + if (txtSearch.getText() == null || txtSearch.getText().isEmpty()) { + displayServices(); + } else { + new Thread(() -> { + try { + List services = ServiceApi.getInstance().listServices(filter); + List serviceDTOs = services.stream() + .map(this::mapToServiceDTO) + .collect(Collectors.toList()); + + Platform.runLater(() -> { + data.setAll(serviceDTOs); + tvServices.setItems(data); + }); + } catch (Exception e) { + Platform.runLater(() -> { + System.out.println("Error while fetching table data: " + e.getMessage()); + ActivityLogger.getInstance().logException( + "ServiceController.displayFilteredServices", + e, + String.format("Filtering services with keyword: %s", filter)); + }); + } + }).start(); } - - String q = text == null ? "" : text.trim().toLowerCase(); - if (q.isEmpty()) { - filtered.setPredicate(s -> true); - return; - } - - filtered.setPredicate(s -> - String.valueOf(s.getServiceId()).contains(q) - || safe(s.getServiceName()).contains(q) - || safe(s.getServiceDesc()).contains(q) - || String.valueOf(s.getServiceDuration()).contains(q) - || String.valueOf(s.getServicePrice()).contains(q) - ); - } - - private static String safe(String v) { - return v == null ? "" : v.toLowerCase(); } @FXML void btnAddClicked(ActionEvent event) { - openDialog(null, "Add"); - loadServices(); + mode = "Add"; + openDialog(null, mode); } @FXML void btnEditClicked(ActionEvent event) { + ServiceDTO selected = tvServices.getSelectionModel().getSelectedItem(); - Service selected = tvServices.getSelectionModel().getSelectedItem(); - - if (selected == null) { - showAlert("Select Service", "Please select a service to edit."); - return; + if (selected != null) { + mode = "Edit"; + openDialog(selected, mode); } - - openDialog(selected, "Edit"); - loadServices(); } @FXML - void btnDeleteClicked(ActionEvent e) { - //get selected services + void btnDeleteClicked(ActionEvent event) { var selectedServices = tvServices.getSelectionModel().getSelectedItems(); if (selectedServices.isEmpty()) return; - //ask user to confirm Alert question = new Alert(Alert.AlertType.CONFIRMATION); question.setHeaderText("Please confirm delete"); String message = selectedServices.size() == 1 @@ -138,82 +156,78 @@ public class ServiceController { : "Are you sure you want to delete " + selectedServices.size() + " services?"; question.setContentText(message); question.getDialogPane().lookupButton(ButtonType.OK).requestFocus(); - java.util.Optional result = question.showAndWait(); + Optional result = question.showAndWait(); - //if confirmed, start deletion if (result.isPresent() && result.get() == ButtonType.OK) { - int successCount = 0; - int failCount = 0; - StringBuilder errors = new StringBuilder(); + List ids = selectedServices.stream() + .map(s -> (long) s.getServiceId()) + .collect(Collectors.toList()); - for (Service service : selectedServices) { - try { - ServiceDB.deleteService(service.getServiceId()); - successCount++; - } catch (Exception ex) { - ActivityLogger.getInstance().logException( - "ServiceController.btnDeleteClicked", - ex, - String.format("Attempting to delete service ID %d", service.getServiceId())); - failCount++; - errors.append("Failed to delete '").append(service.getServiceName()).append("'\n"); - } - } - - //show results - if (failCount > 0) { - Alert alert = new Alert(Alert.AlertType.WARNING); - alert.setHeaderText("Delete Operation Completed with Errors"); - alert.setContentText(String.format("Deleted: %d\nFailed: %d\n\n%s", - successCount, failCount, errors.toString())); - alert.showAndWait(); - } else if (successCount > 0) { + try { + ServiceApi.getInstance().deleteServices(ids); Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setHeaderText("Database Operation Confirmed"); - alert.setContentText("Successfully deleted " + successCount + " service(s)"); + alert.setContentText("Successfully deleted " + ids.size() + " service(s)"); + alert.showAndWait(); + } catch (Exception e) { + ActivityLogger.getInstance().logException( + "ServiceController.btnDeleteClicked", + e, + "Deleting services"); + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Delete Operation Failed"); + alert.setContentText(e.getMessage()); alert.showAndWait(); } - //refresh display - loadServices(); + displayServices(); + btnDelete.setDisable(true); + btnEdit.setDisable(true); + txtSearch.setText(""); } } - private void openDialog(Service service, String mode) { - + private void openDialog(ServiceDTO service, String mode) { + FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/service-dialog-view.fxml")); + Scene scene = null; try { - FXMLLoader loader = new FXMLLoader( - getClass().getResource("/org/example/petshopdesktop/dialogviews/service-dialog-view.fxml") - ); - - Stage stage = new Stage(); - stage.setScene(new Scene(loader.load())); - - ServiceDialogController controller = loader.getController(); - controller.setMode(mode); - - if (mode.equals("Edit")) { - controller.setService(service); - } - - stage.initModality(Modality.APPLICATION_MODAL); - stage.showAndWait(); - - loadServices(); - + scene = new Scene(fxmlLoader.load()); } catch (Exception e) { ActivityLogger.getInstance().logException( "ServiceController.openDialog", e, - "Opening service dialog in " + mode + " mode"); - e.printStackTrace(); + String.format("Loading service dialog view in %s mode", mode)); + throw new RuntimeException(e); } + ServiceDialogController dialogController = fxmlLoader.getController(); + dialogController.setMode(mode); + + if (mode.equals("Edit")) { + dialogController.setService(service); + } + Stage dialogStage = new Stage(); + dialogStage.initModality(Modality.APPLICATION_MODAL); + if (mode.equals("Add")) { + dialogStage.setTitle("Add Service"); + } else { + dialogStage.setTitle("Edit Service"); + } + dialogStage.setScene(scene); + dialogStage.showAndWait(); + + displayServices(); + btnDelete.setDisable(true); + btnEdit.setDisable(true); + txtSearch.setText(""); } - private void showAlert(String title, String msg) { - Alert alert = new Alert(Alert.AlertType.INFORMATION); - alert.setTitle(title); - alert.setHeaderText(null); - alert.setContentText(msg); - alert.showAndWait(); + + private ServiceDTO mapToServiceDTO(ServiceResponse response) { + return new ServiceDTO( + response.getId().intValue(), + response.getServiceName(), + response.getDescription(), + 0, + response.getPrice().doubleValue() + ); } } \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/controllers/StaffAccountsController.java b/src/main/java/org/example/petshopdesktop/controllers/StaffAccountsController.java index 6006bb15..eefcb73d 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/StaffAccountsController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/StaffAccountsController.java @@ -1,5 +1,6 @@ package org.example.petshopdesktop.controllers; +import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.collections.transformation.FilteredList; @@ -15,12 +16,16 @@ import javafx.scene.control.TextField; import javafx.scene.control.cell.PropertyValueFactory; import javafx.stage.Modality; import javafx.stage.Stage; +import org.example.petshopdesktop.api.dto.user.UserResponse; +import org.example.petshopdesktop.api.endpoints.UserApi; import org.example.petshopdesktop.auth.UserSession; -import org.example.petshopdesktop.database.UserDB; import org.example.petshopdesktop.models.StaffAccount; import org.example.petshopdesktop.util.ActivityLogger; -import java.sql.SQLException; +import java.sql.Timestamp; +import java.time.ZoneId; +import java.util.List; +import java.util.stream.Collectors; public class StaffAccountsController { @@ -107,15 +112,54 @@ public class StaffAccountsController { private void refresh() { lblError.setText(""); - try { - staffAccounts.setAll(UserDB.getStaffAccounts()); - } catch (SQLException e) { - ActivityLogger.getInstance().logException("StaffAccountsController.refresh", e, "Loading staff accounts"); - lblError.setText("Could not load staff accounts."); - } catch (RuntimeException e) { - ActivityLogger.getInstance().logException("StaffAccountsController.refresh", e, "Database connection"); - lblError.setText("Database is not connected."); + tvStaff.setDisable(true); + + new Thread(() -> { + try { + List users = UserApi.getInstance().listUsers(null); + List accounts = users.stream() + .map(this::mapToStaffAccount) + .collect(Collectors.toList()); + + Platform.runLater(() -> { + staffAccounts.setAll(accounts); + tvStaff.setDisable(false); + }); + } catch (Exception e) { + ActivityLogger.getInstance().logException("StaffAccountsController.refresh", e, "Loading staff accounts"); + Platform.runLater(() -> { + lblError.setText("Could not load staff accounts."); + tvStaff.setDisable(false); + }); + } + }).start(); + } + + private StaffAccount mapToStaffAccount(UserResponse user) { + long id = user.getId() != null ? user.getId() : 0L; + String username = user.getUsername(); + String fullName = user.getFullName() != null ? user.getFullName() : ""; + String[] names = splitFullName(fullName); + String firstName = names[0]; + String lastName = names[1]; + String email = ""; + String phone = ""; + boolean active = user.getActive() != null ? user.getActive() : false; + Timestamp createdAt = user.getCreatedAt() != null + ? Timestamp.from(user.getCreatedAt().atZone(ZoneId.systemDefault()).toInstant()) + : null; + + return new StaffAccount(id, id, username, firstName, lastName, email, phone, active, createdAt); + } + + private String[] splitFullName(String fullName) { + if (fullName == null || fullName.trim().isEmpty()) { + return new String[]{"", ""}; } + String[] parts = fullName.trim().split("\\s+", 2); + String firstName = parts.length > 0 ? parts[0] : ""; + String lastName = parts.length > 1 ? parts[1] : ""; + return new String[]{firstName, lastName}; } private void applyFilter(String text) { diff --git a/src/main/java/org/example/petshopdesktop/controllers/SupplierController.java b/src/main/java/org/example/petshopdesktop/controllers/SupplierController.java index 049bddbd..144c85ea 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/SupplierController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/SupplierController.java @@ -1,5 +1,6 @@ package org.example.petshopdesktop.controllers; +import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.ActionEvent; @@ -10,15 +11,16 @@ import javafx.scene.control.*; import javafx.scene.control.cell.PropertyValueFactory; import javafx.stage.Modality; import javafx.stage.Stage; +import org.example.petshopdesktop.api.dto.supplier.SupplierResponse; +import org.example.petshopdesktop.api.endpoints.SupplierApi; import org.example.petshopdesktop.controllers.dialogcontrollers.SupplierDialogController; -import org.example.petshopdesktop.database.SupplierDB; import org.example.petshopdesktop.models.Supplier; import org.example.petshopdesktop.util.ActivityLogger; import java.io.IOException; -import java.sql.SQLException; -import java.sql.SQLIntegrityConstraintViolationException; +import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; /** * The controller for any operations in the supplier view @@ -105,19 +107,27 @@ public class SupplierController { * Display the suppliers to table view */ private void displaySupplier(){ - data.clear(); + new Thread(() -> { + try { + List suppliers = SupplierApi.getInstance().listSuppliers(null); + List supplierList = suppliers.stream() + .map(this::mapToSupplier) + .collect(Collectors.toList()); - try{ - data = SupplierDB.getSuppliers(); - } catch (SQLException e) { - ActivityLogger.getInstance().logException( - "SupplierController.displaySupplier", - e, - "Fetching supplier data for table display"); - System.out.println("Error while fetching table data: " + e.getMessage()); - } - - tvSuppliers.setItems(data); + Platform.runLater(() -> { + data.setAll(supplierList); + tvSuppliers.setItems(data); + }); + } catch (Exception e) { + Platform.runLater(() -> { + System.out.println("Error while fetching table data: " + e.getMessage()); + ActivityLogger.getInstance().logException( + "SupplierController.displaySupplier", + e, + "Fetching supplier data for table display"); + }); + } + }).start(); } /** @@ -125,22 +135,30 @@ public class SupplierController { * @param filter word to filter table */ private void displayFilteredSupplier(String filter){ - data.clear(); - try{ - if (txtSearch.getText() == null || txtSearch.getText().isEmpty()){ - displaySupplier(); //If search bar is empty just display everything - } - else{ - //Filter the using the keyword - data = SupplierDB.getFilteredSuppliers(filter); - tvSuppliers.setItems(data); - } - } catch (Exception e) { - ActivityLogger.getInstance().logException( - "SupplierController.displayFilteredSupplier", - e, - "Filtering suppliers with filter: " + filter); - System.out.println("Error while fetching table data: " + e.getMessage()); + if (txtSearch.getText() == null || txtSearch.getText().isEmpty()){ + displaySupplier(); + } else { + new Thread(() -> { + try { + List suppliers = SupplierApi.getInstance().listSuppliers(filter); + List supplierList = suppliers.stream() + .map(this::mapToSupplier) + .collect(Collectors.toList()); + + Platform.runLater(() -> { + data.setAll(supplierList); + tvSuppliers.setItems(data); + }); + } catch (Exception e) { + Platform.runLater(() -> { + System.out.println("Error while fetching table data: " + e.getMessage()); + ActivityLogger.getInstance().logException( + "SupplierController.displayFilteredSupplier", + e, + "Filtering suppliers with filter: " + filter); + }); + } + }).start(); } } @@ -177,48 +195,24 @@ public class SupplierController { //if confirmed, start deletion if (result.isPresent() && result.get() == ButtonType.OK) { - int successCount = 0; - int failCount = 0; - StringBuilder errors = new StringBuilder(); + List ids = selectedSuppliers.stream() + .map(s -> (long) s.getSupId()) + .collect(Collectors.toList()); - for (Supplier supplier : selectedSuppliers) { - try{ - int numRows = SupplierDB.deleteSupplier(supplier.getSupId()); - if (numRows > 0) { - successCount++; - } else { - failCount++; - } - } - catch (SQLIntegrityConstraintViolationException e){ - ActivityLogger.getInstance().logException( - "SupplierController.btnDeleteClicked", - e, - String.format("Attempting to delete supplier ID %d - foreign key constraint", supplier.getSupId())); - failCount++; - errors.append("Supplier '").append(supplier.getSupCompany()).append("' is referenced in another table\n"); - } - catch (SQLException e) { - ActivityLogger.getInstance().logException( - "SupplierController.btnDeleteClicked", - e, - String.format("Attempting to delete supplier ID %d", supplier.getSupId())); - failCount++; - errors.append("Failed to delete '").append(supplier.getSupCompany()).append("'\n"); - } - } - - //show results - if (failCount > 0) { - Alert alert = new Alert(Alert.AlertType.WARNING); - alert.setHeaderText("Delete Operation Completed with Errors"); - alert.setContentText(String.format("Deleted: %d\nFailed: %d\n\n%s", - successCount, failCount, errors.toString())); - alert.showAndWait(); - } else if (successCount > 0) { + try { + SupplierApi.getInstance().deleteSuppliers(ids); Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setHeaderText("Database Operation Confirmed"); - alert.setContentText("Successfully deleted " + successCount + " supplier(s)"); + alert.setContentText("Successfully deleted " + ids.size() + " supplier(s)"); + alert.showAndWait(); + } catch (Exception e) { + ActivityLogger.getInstance().logException( + "SupplierController.btnDeleteClicked", + e, + "Deleting suppliers"); + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Delete Operation Failed"); + alert.setContentText(e.getMessage()); alert.showAndWait(); } @@ -290,4 +284,20 @@ public class SupplierController { txtSearch.setText(""); } + private Supplier mapToSupplier(SupplierResponse response) { + String contactPerson = response.getContactPerson() != null ? response.getContactPerson() : ""; + String[] nameParts = contactPerson.split(" ", 2); + String firstName = nameParts.length > 0 ? nameParts[0] : ""; + String lastName = nameParts.length > 1 ? nameParts[1] : ""; + + return new Supplier( + response.getId().intValue(), + response.getSupplierName(), + firstName, + lastName, + response.getEmail(), + response.getPhone() + ); + } + } \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/AdoptionDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/AdoptionDialogController.java index 213426f9..ed1fca7c 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/AdoptionDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/AdoptionDialogController.java @@ -1,5 +1,6 @@ package org.example.petshopdesktop.controllers.dialogcontrollers; +import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.EventHandler; @@ -12,16 +13,15 @@ import javafx.scene.control.DatePicker; import javafx.scene.control.Label; import javafx.scene.input.MouseEvent; import javafx.stage.Stage; -import javafx.util.StringConverter; -import org.example.petshopdesktop.database.AdoptionDB; -import org.example.petshopdesktop.database.PetDB; +import org.example.petshopdesktop.api.dto.adoption.AdoptionRequest; +import org.example.petshopdesktop.api.dto.common.DropdownOption; +import org.example.petshopdesktop.api.endpoints.AdoptionApi; +import org.example.petshopdesktop.api.endpoints.DropdownApi; import org.example.petshopdesktop.models.Adoption; -import org.example.petshopdesktop.models.Customer; -import org.example.petshopdesktop.models.Pet; import org.example.petshopdesktop.util.ActivityLogger; -import java.sql.SQLException; import java.time.LocalDate; +import java.util.List; public class AdoptionDialogController { @@ -36,10 +36,10 @@ public class AdoptionDialogController { private ComboBox cbAdoptionStatus; @FXML - private ComboBox cbCustomer; + private ComboBox cbCustomer; @FXML - private ComboBox cbPet; + private ComboBox cbPet; @FXML private DatePicker dpAdoptionDate; @@ -58,52 +58,47 @@ public class AdoptionDialogController { "Pending", "Completed", "Cancelled" ); - //Loads upon boot @FXML void initialize() { - //Loads statusList into combo box cbAdoptionStatus.setItems(statusList); - //Pet objects are converted into readable text for combobox (PetID + PetName) - cbPet.setConverter(new StringConverter() { - @Override - public String toString(Pet pet) { - return pet == null ? "" : pet.getPetId() + ": " + pet.getPetName(); + new Thread(() -> { + try { + List pets = DropdownApi.getInstance().getPets(); + Platform.runLater(() -> { + ObservableList petsObs = FXCollections.observableArrayList(pets); + cbPet.setItems(petsObs); + }); + } catch (Exception e) { + Platform.runLater(() -> { + ActivityLogger.getInstance().logException( + "AdoptionDialogController.initialize", + e, + "Loading pets for combo box"); + System.out.println("Error loading pets: " + e.getMessage()); + }); } + }).start(); - //Not used - @Override - public Pet fromString(String string) { return null; } - }); + new Thread(() -> { + try { + List customers = DropdownApi.getInstance().getCustomers(); + Platform.runLater(() -> { + ObservableList customersObs = FXCollections.observableArrayList(customers); + cbCustomer.setItems(customersObs); + }); + } catch (Exception e) { + Platform.runLater(() -> { + ActivityLogger.getInstance().logException( + "AdoptionDialogController.initialize", + e, + "Loading customers for combo box"); + System.out.println("Error loading customers: " + e.getMessage()); + }); + } + }).start(); - //Load pets from DB into pet combobox - try { - cbPet.setItems(PetDB.getPets()); - } - - catch (SQLException e) { - ActivityLogger.getInstance().logException( - "AdoptionDialogController.initialize", - e, - "Loading pets for combo box"); - System.out.println("Error loading pets: " + e.getMessage()); - } - - //Load customers from DB into customer combobox - try { - cbCustomer.setItems(AdoptionDB.getCustomers()); - } - - catch (SQLException e) { - ActivityLogger.getInstance().logException( - "AdoptionDialogController.initialize", - e, - "Loading customers for combo box"); - System.out.println("Error loading customers: " + e.getMessage()); - } - - //Save button handler btnSave.setOnMouseClicked(new EventHandler() { @Override public void handle(MouseEvent mouseEvent) { @@ -111,7 +106,6 @@ public class AdoptionDialogController { } }); - //Cancel button handler, closes dialog view btnCancel.setOnMouseClicked(new EventHandler() { @Override public void handle(MouseEvent mouseEvent) { @@ -120,12 +114,9 @@ public class AdoptionDialogController { }); } - //Handles logic when clicking Save private void buttonSaveClicked(MouseEvent mouseEvent) { - int numRow = 0; String errorMsg = ""; - //Validation: checks if anything is missing if (cbPet.getSelectionModel().getSelectedItem() == null) { errorMsg += "Pet is required.\n"; } @@ -142,60 +133,37 @@ public class AdoptionDialogController { errorMsg += "Status is required.\n"; } - //If no errors, attempt DB operation if (errorMsg.isEmpty()) { - Adoption adoption = collectAdoption(); + try { + AdoptionRequest request = new AdoptionRequest(); + request.setPetId(cbPet.getSelectionModel().getSelectedItem().getId()); + request.setCustomerId(cbCustomer.getSelectionModel().getSelectedItem().getId()); + request.setAdoptionDate(dpAdoptionDate.getValue()); + request.setAdoptionStatus(cbAdoptionStatus.getValue()); - //Try inserting into DB - if (mode.equals("Add")) { - try { - numRow = AdoptionDB.insertAdoption(adoption); + if (mode.equals("Add")) { + AdoptionApi.getInstance().createAdoption(request); + } else { + Long adoptionId = Long.parseLong(lblAdoptionId.getText().split(": ")[1]); + AdoptionApi.getInstance().updateAdoption(adoptionId, request); } - catch (SQLException e) { - ActivityLogger.getInstance().logException( - "AdoptionDialogController.buttonSaveClicked", - e, - "Inserting new adoption record"); - throw new RuntimeException(e); - } - } - - //Try updating adoption - else { - try { - numRow = AdoptionDB.updateAdoption(adoption.getAdoptionId(), adoption); - } - - catch (SQLException e) { - ActivityLogger.getInstance().logException( - "AdoptionDialogController.buttonSaveClicked", - e, - "Updating adoption with ID: " + adoption.getAdoptionId()); - throw new RuntimeException(e); - } - } - - //If no rows are affected, an issue has occurred - if (numRow == 0) { - Alert alert = new Alert(Alert.AlertType.ERROR); - alert.setHeaderText("Database Operation Error"); - alert.setContentText(mode + " failed"); - alert.showAndWait(); - } - - //DB operation worked! - else { Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setHeaderText("Saved"); alert.setContentText(mode + " succeeded"); alert.showAndWait(); closeStage(mouseEvent); + } catch (Exception e) { + ActivityLogger.getInstance().logException( + "AdoptionDialogController.buttonSaveClicked", + e, + mode + " adoption"); + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Database Operation Error"); + alert.setContentText(e.getMessage()); + alert.showAndWait(); } - } - - //If there are errors, display them - else { + } else { Alert alert = new Alert(Alert.AlertType.ERROR); alert.setHeaderText("Input Error"); alert.setContentText(errorMsg); @@ -203,30 +171,6 @@ public class AdoptionDialogController { } } - //Collects user input, builds an Adoption object - private Adoption collectAdoption() { - int adoptionId = 0; - - //Only grab adoption ID if in edit mode - if (lblAdoptionId.isVisible()) { - adoptionId = Integer.parseInt(lblAdoptionId.getText().split(": ")[1]); - } - - Pet selectedPet = cbPet.getSelectionModel().getSelectedItem(); - Customer selectedCustomer = cbCustomer.getSelectionModel().getSelectedItem(); - String date = dpAdoptionDate.getValue().toString(); - String status = cbAdoptionStatus.getValue(); - - return new Adoption( - adoptionId, - selectedPet.getPetId(), - selectedCustomer.getCustomerId(), - selectedCustomer.toString(), - date, - selectedPet.getPetPrice(), - status - ); - } private void closeStage(MouseEvent mouseEvent) { Node node = (Node) mouseEvent.getSource(); @@ -234,35 +178,28 @@ public class AdoptionDialogController { stage.close(); } - //Edit mode - //Inserts data into fields public void displayAdoptionDetails(Adoption adoption) { if (adoption != null) { - //Displays adoption ID lblAdoptionId.setText("ID: " + adoption.getAdoptionId()); - //Select pet - for (Pet pet : cbPet.getItems()) { - if (pet.getPetId() == adoption.getPetId()) { + for (DropdownOption pet : cbPet.getItems()) { + if (pet.getLabel().equals(adoption.getPetName())) { cbPet.getSelectionModel().select(pet); break; } } - //Select customer - for (Customer customer : cbCustomer.getItems()) { - if (customer.getCustomerId() == adoption.getCustomerId()) { + for (DropdownOption customer : cbCustomer.getItems()) { + if (customer.getLabel().equals(adoption.getCustomerName())) { cbCustomer.getSelectionModel().select(customer); break; } } - //Select adoption date if (adoption.getAdoptionDate() != null && !adoption.getAdoptionDate().isEmpty()) { dpAdoptionDate.setValue(LocalDate.parse(adoption.getAdoptionDate())); } - //Select adoption status for (String status : cbAdoptionStatus.getItems()) { if (status.equals(adoption.getAdoptionStatus())) { cbAdoptionStatus.getSelectionModel().select(status); @@ -272,8 +209,6 @@ public class AdoptionDialogController { } } - //Sets dialog mode - //Also updates label and adoption ID visibility public void setMode(String mode) { this.mode = mode; lblMode.setText(mode + " Adoption"); diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/AppointmentDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/AppointmentDialogController.java index 411e230b..ecefa73c 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/AppointmentDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/AppointmentDialogController.java @@ -1,5 +1,6 @@ package org.example.petshopdesktop.controllers.dialogcontrollers; +import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.fxml.FXML; @@ -10,11 +11,16 @@ import javafx.stage.Stage; import javafx.scene.control.ListCell; import org.example.petshopdesktop.DTOs.AppointmentDTO; -import org.example.petshopdesktop.database.*; -import org.example.petshopdesktop.models.*; +import org.example.petshopdesktop.api.dto.appointment.AppointmentRequest; +import org.example.petshopdesktop.api.dto.appointment.AppointmentResponse; +import org.example.petshopdesktop.api.dto.common.DropdownOption; +import org.example.petshopdesktop.api.endpoints.AppointmentApi; +import org.example.petshopdesktop.api.endpoints.DropdownApi; import org.example.petshopdesktop.util.ActivityLogger; -import java.sql.Time; +import java.time.LocalTime; +import java.util.Collections; +import java.util.List; public class AppointmentDialogController { @@ -25,9 +31,9 @@ public class AppointmentDialogController { @FXML private Button btnCancel; @FXML private Button btnSave; - @FXML private ComboBox cbService; - @FXML private ComboBox cbCustomer; - @FXML private ComboBox cbPet; + @FXML private ComboBox cbService; + @FXML private ComboBox cbCustomer; + @FXML private ComboBox cbPet; @FXML private ComboBox cbHour; @FXML private ComboBox cbMinute; @@ -67,17 +73,27 @@ public class AppointmentDialogController { @FXML public void initialize() { - try { - cbService.setItems(ServiceDB.getServices()); - cbCustomer.setItems(CustomerDB.getCustomers()); - cbPet.setItems(PetDB.getPets()); - } catch (Exception e) { - ActivityLogger.getInstance().logException( - "AppointmentDialogController.initialize", - e, - "Loading combo box data for services, customers, and pets"); - e.printStackTrace(); - } + new Thread(() -> { + try { + List services = DropdownApi.getInstance().getServices(); + List customers = DropdownApi.getInstance().getCustomers(); + List pets = DropdownApi.getInstance().getPets(); + + Platform.runLater(() -> { + cbService.setItems(FXCollections.observableArrayList(services)); + cbCustomer.setItems(FXCollections.observableArrayList(customers)); + cbPet.setItems(FXCollections.observableArrayList(pets)); + }); + } catch (Exception e) { + Platform.runLater(() -> { + ActivityLogger.getInstance().logException( + "AppointmentDialogController.initialize", + e, + "Loading combo box data for services, customers, and pets"); + e.printStackTrace(); + }); + } + }).start(); cbAppointmentStatus.setItems(statusList); @@ -88,20 +104,49 @@ public class AppointmentDialogController { cbMinute.getItems().addAll(0, 15, 30, 45); - // Show pet name - cbPet.setCellFactory(param -> new ListCell<>() { + // Show dropdown labels + cbService.setCellFactory(param -> new ListCell<>() { @Override - protected void updateItem(Pet pet, boolean empty) { - super.updateItem(pet, empty); - setText(empty || pet == null ? null : pet.getPetName()); + protected void updateItem(DropdownOption option, boolean empty) { + super.updateItem(option, empty); + setText(empty || option == null ? null : option.getLabel()); + } + }); + cbService.setButtonCell(new ListCell<>() { + @Override + protected void updateItem(DropdownOption option, boolean empty) { + super.updateItem(option, empty); + setText(empty || option == null ? null : option.getLabel()); } }); + cbCustomer.setCellFactory(param -> new ListCell<>() { + @Override + protected void updateItem(DropdownOption option, boolean empty) { + super.updateItem(option, empty); + setText(empty || option == null ? null : option.getLabel()); + } + }); + cbCustomer.setButtonCell(new ListCell<>() { + @Override + protected void updateItem(DropdownOption option, boolean empty) { + super.updateItem(option, empty); + setText(empty || option == null ? null : option.getLabel()); + } + }); + + cbPet.setCellFactory(param -> new ListCell<>() { + @Override + protected void updateItem(DropdownOption option, boolean empty) { + super.updateItem(option, empty); + setText(empty || option == null ? null : option.getLabel()); + } + }); cbPet.setButtonCell(new ListCell<>() { @Override - protected void updateItem(Pet pet, boolean empty) { - super.updateItem(pet, empty); - setText(empty || pet == null ? null : pet.getPetName()); + protected void updateItem(DropdownOption option, boolean empty) { + super.updateItem(option, empty); + setText(empty || option == null ? null : option.getLabel()); } }); @@ -124,20 +169,20 @@ public class AppointmentDialogController { cbAppointmentStatus.setValue(appt.getAppointmentStatus()); - Time time = Time.valueOf(appt.getAppointmentTime()); - cbHour.setValue(time.toLocalTime().getHour()); - cbMinute.setValue(time.toLocalTime().getMinute()); + LocalTime time = LocalTime.parse(appt.getAppointmentTime()); + cbHour.setValue(time.getHour()); + cbMinute.setValue(time.getMinute()); cbService.getItems().forEach(s -> { - if (s.getServiceId() == appt.getServiceId()) cbService.setValue(s); + if (s.getId() == appt.getServiceId()) cbService.setValue(s); }); cbCustomer.getItems().forEach(c -> { - if (c.getCustomerId() == appt.getCustomerId()) cbCustomer.setValue(c); + if (c.getId() == appt.getCustomerId()) cbCustomer.setValue(c); }); cbPet.getItems().forEach(p -> { - if (p.getPetId() == appt.getPetId()) cbPet.setValue(p); + if (p.getId() == appt.getPetId()) cbPet.setValue(p); }); } @@ -159,45 +204,40 @@ public class AppointmentDialogController { return; } - Time appointmentTime = - Time.valueOf(String.format( - "%02d:%02d:00", - cbHour.getValue(), - cbMinute.getValue() - )); + LocalTime appointmentTime = LocalTime.of(cbHour.getValue(), cbMinute.getValue()); - Appointment appt = new Appointment( - selectedAppointment == null ? 0 : selectedAppointment.getAppointmentId(), - cbService.getValue().getServiceId(), - cbCustomer.getValue().getCustomerId(), - dpAppointmentDate.getValue().toString(), - appointmentTime.toString(), - cbAppointmentStatus.getValue() - ); + AppointmentRequest request = new AppointmentRequest(); + request.setPetIds(Collections.singletonList(cbPet.getValue().getId())); + request.setCustomerId(cbCustomer.getValue().getId()); + request.setServiceId(cbService.getValue().getId()); + request.setAppointmentDate(dpAppointmentDate.getValue()); + request.setAppointmentTime(appointmentTime); + request.setAppointmentStatus(cbAppointmentStatus.getValue()); - try { + new Thread(() -> { + try { + if (mode.equals("Add")) { + AppointmentApi.getInstance().createAppointment(request); + } else { + AppointmentApi.getInstance().updateAppointment( + (long) selectedAppointment.getAppointmentId(), + request + ); + } - if (mode.equals("Add")) { - int newId = AppointmentDB.insertAppointment(appt); - AppointmentDB.insertAppointmentPet(newId, cbPet.getValue().getPetId()); - } else { - AppointmentDB.updateAppointment( - selectedAppointment.getAppointmentId(), - appt, - cbPet.getValue().getPetId() - ); + Platform.runLater(() -> closeStage(e)); + + } catch (Exception ex) { + Platform.runLater(() -> { + ActivityLogger.getInstance().logException( + "AppointmentDialogController.buttonSaveClicked", + ex, + "Saving appointment in " + mode + " mode"); + ex.printStackTrace(); + showError("Error saving appointment: " + ex.getMessage()); + }); } - - closeStage(e); - - } catch (Exception ex) { - ActivityLogger.getInstance().logException( - "AppointmentDialogController.buttonSaveClicked", - ex, - "Saving appointment in " + mode + " mode"); - ex.printStackTrace(); - showError("Error saving appointment"); - } + }).start(); } // diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductSupplierDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductSupplierDialogController.java index 154c62fd..a94a6012 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductSupplierDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductSupplierDialogController.java @@ -1,5 +1,6 @@ package org.example.petshopdesktop.controllers.dialogcontrollers; +import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.EventHandler; @@ -10,16 +11,14 @@ import javafx.scene.input.MouseEvent; import javafx.stage.Stage; import org.example.petshopdesktop.DTOs.ProductSupplierDTO; import org.example.petshopdesktop.Validator; -import org.example.petshopdesktop.database.ProductDB; -import org.example.petshopdesktop.database.ProductSupplierDB; -import org.example.petshopdesktop.database.SupplierDB; -import org.example.petshopdesktop.models.Product; -import org.example.petshopdesktop.models.ProductSupplier; -import org.example.petshopdesktop.models.Supplier; +import org.example.petshopdesktop.api.dto.common.DropdownOption; +import org.example.petshopdesktop.api.dto.productsupplier.ProductSupplierRequest; +import org.example.petshopdesktop.api.dto.productsupplier.ProductSupplierResponse; +import org.example.petshopdesktop.api.endpoints.DropdownApi; +import org.example.petshopdesktop.api.endpoints.ProductSupplierApi; import org.example.petshopdesktop.util.ActivityLogger; -import java.sql.SQLException; -import java.sql.SQLIntegrityConstraintViolationException; +import java.math.BigDecimal; public class ProductSupplierDialogController { @@ -30,10 +29,10 @@ public class ProductSupplierDialogController { private Button btnSave; @FXML - private ComboBox cbProduct; + private ComboBox cbProduct; @FXML - private ComboBox cbSupplier; + private ComboBox cbSupplier; @FXML private Label lblMode; @@ -47,6 +46,7 @@ public class ProductSupplierDialogController { private String mode = null; private int selectedSupId = -1; private int selectedProdId = -1; + private Long selectedId = null; /** * add event listeners to buttons and set up combobox @@ -67,26 +67,74 @@ public class ProductSupplierDialogController { } }); - //Set up combobox for selecting product and supplier - try{ - ObservableList suppliers = FXCollections.observableArrayList(); //empty list - ObservableList products = FXCollections.observableArrayList(); //empty list + cbSupplier.setButtonCell(new ListCell() { + @Override + protected void updateItem(DropdownOption item, boolean empty) { + super.updateItem(item, empty); + if (empty || item == null) { + setText(null); + } else { + setText(item.getLabel()); + } + } + }); + cbSupplier.setCellFactory(lv -> new ListCell() { + @Override + protected void updateItem(DropdownOption item, boolean empty) { + super.updateItem(item, empty); + if (empty || item == null) { + setText(null); + } else { + setText(item.getLabel()); + } + } + }); - //get suppliers and products from DB - suppliers = SupplierDB.getSuppliers(); - products = ProductDB.getProducts(); + cbProduct.setButtonCell(new ListCell() { + @Override + protected void updateItem(DropdownOption item, boolean empty) { + super.updateItem(item, empty); + if (empty || item == null) { + setText(null); + } else { + setText(item.getLabel()); + } + } + }); + cbProduct.setCellFactory(lv -> new ListCell() { + @Override + protected void updateItem(DropdownOption item, boolean empty) { + super.updateItem(item, empty); + if (empty || item == null) { + setText(null); + } else { + setText(item.getLabel()); + } + } + }); - //Populate combobox - cbSupplier.setItems(suppliers); - cbProduct.setItems(products); - } - catch(SQLException e){ - ActivityLogger.getInstance().logException( - "ProductSupplierDialogController.initialize", - e, - "Loading suppliers and products for combo boxes"); - throw new RuntimeException(e); - } + new Thread(() -> { + try { + var suppliers = DropdownApi.getInstance().getSuppliers(); + var products = DropdownApi.getInstance().getProducts(); + + Platform.runLater(() -> { + cbSupplier.setItems(FXCollections.observableArrayList(suppliers)); + cbProduct.setItems(FXCollections.observableArrayList(products)); + }); + } catch (Exception e) { + Platform.runLater(() -> { + ActivityLogger.getInstance().logException( + "ProductSupplierDialogController.initialize", + e, + "Loading suppliers and products for combo boxes"); + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Initialization Error"); + alert.setContentText("Failed to load dropdown data: " + e.getMessage()); + alert.showAndWait(); + }); + } + }).start(); } @@ -96,10 +144,8 @@ public class ProductSupplierDialogController { * @param mouseEvent click event for save button */ private void buttonSaveClicked(MouseEvent mouseEvent) { - int numRows = 0; - String errorMsg = ""; //error message for validation + String errorMsg = ""; - //Check Validation (input required) errorMsg += Validator.isPresent(txtCost.getText(), "Cost"); if (cbProduct.getSelectionModel().getSelectedItem() == null) { errorMsg += "Product is required \n"; @@ -108,82 +154,41 @@ public class ProductSupplierDialogController { errorMsg += "Supplier is required \n"; } - //Check validation (length size) errorMsg += Validator.isLessThanVarChars(txtCost.getText(), "Cost", 12); - - //Check validation (format) errorMsg += Validator.isNonNegativeDouble(txtCost.getText(), "Cost"); - if(errorMsg.isEmpty()){ //no validation errors - ProductSupplier productSupplier = collectProductSupplier(); //get productSupplier info - if (mode.equals("Add")) { //add mode - try{ - numRows = ProductSupplierDB.insertProductSupplier(productSupplier); - } - catch(SQLIntegrityConstraintViolationException e){ - ActivityLogger.getInstance().logException( - "ProductSupplierDialogController.buttonSaveClicked", - e, - "Inserting product-supplier (integrity constraint violation)"); - Alert alert = new Alert(Alert.AlertType.ERROR); - alert.setHeaderText("Database Operation Error"); - alert.setContentText("Add failed \n" + - "the product-supplier link is already in the database"); - alert.showAndWait(); - numRows = -1; //Update numRow so alert only shows once - closeStage(mouseEvent); - } - catch(SQLException e){ - ActivityLogger.getInstance().logException( - "ProductSupplierDialogController.buttonSaveClicked", - e, - "Inserting new product-supplier record"); - throw new RuntimeException(e); - } - } - else { //edit - try{ - numRows = ProductSupplierDB.updateProductSupplier(selectedSupId, selectedProdId, productSupplier); - } - catch(SQLIntegrityConstraintViolationException e){ - ActivityLogger.getInstance().logException( - "ProductSupplierDialogController.buttonSaveClicked", - e, - "Updating product-supplier (integrity constraint violation) - SupID: " + selectedSupId + ", ProdID: " + selectedProdId); - Alert alert = new Alert(Alert.AlertType.ERROR); - alert.setHeaderText("Database Operation Error"); - alert.setContentText("Edit failed \n" + - "the product-supplier link is already in the database"); - alert.showAndWait(); - numRows = -1; //Update numRow so alert only shows once - closeStage(mouseEvent); - } - catch(SQLException e){ - ActivityLogger.getInstance().logException( - "ProductSupplierDialogController.buttonSaveClicked", - e, - "Updating product-supplier - SupID: " + selectedSupId + ", ProdID: " + selectedProdId); - throw new RuntimeException(e); - } - } + if(errorMsg.isEmpty()){ + ProductSupplierRequest request = collectProductSupplierRequest(); - //if no rows were affected then there was an error (prompt user of error) - if (numRows == 0){ - Alert alert = new Alert(Alert.AlertType.ERROR); - alert.setHeaderText("Database Operation Error"); - alert.setContentText(mode + " failed"); - alert.showAndWait(); - } - else if (numRows > 0){ - //tell the user operation was successful - Alert alert = new Alert(Alert.AlertType.INFORMATION); - alert.setHeaderText("Saved"); - alert.setContentText(mode + " succeeded"); - alert.showAndWait(); - closeStage(mouseEvent); - } - } - else { //Display validation errors + new Thread(() -> { + try { + if (mode.equals("Add")) { + ProductSupplierApi.getInstance().createProductSupplier(request); + } else { + ProductSupplierApi.getInstance().updateProductSupplier(selectedId, request); + } + + Platform.runLater(() -> { + Alert alert = new Alert(Alert.AlertType.INFORMATION); + alert.setHeaderText("Saved"); + alert.setContentText(mode + " succeeded"); + alert.showAndWait(); + closeStage(mouseEvent); + }); + } catch (Exception e) { + Platform.runLater(() -> { + ActivityLogger.getInstance().logException( + "ProductSupplierDialogController.buttonSaveClicked", + e, + mode + " product-supplier"); + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Database Operation Error"); + alert.setContentText(mode + " failed: " + e.getMessage()); + alert.showAndWait(); + }); + } + }).start(); + } else { Alert alert = new Alert(Alert.AlertType.ERROR); alert.setHeaderText("Input Error"); alert.setContentText(errorMsg); @@ -193,18 +198,14 @@ public class ProductSupplierDialogController { /** * collect the data for new/updated productSupplier - * @return productSupplier entity with data + * @return productSupplier request with data */ - private ProductSupplier collectProductSupplier() { - ProductSupplier productSupplier = null; - - productSupplier = new ProductSupplier( - cbSupplier.getSelectionModel().getSelectedItem().getSupId(), - cbProduct.getSelectionModel().getSelectedItem().getProdId(), - Double.parseDouble(txtCost.getText()) - ); - - return productSupplier; + private ProductSupplierRequest collectProductSupplierRequest() { + ProductSupplierRequest request = new ProductSupplierRequest(); + request.setSupplierId(cbSupplier.getSelectionModel().getSelectedItem().getId()); + request.setProductId(cbProduct.getSelectionModel().getSelectedItem().getId()); + request.setSupplierPrice(new BigDecimal(txtCost.getText())); + return request; } /** @@ -216,20 +217,17 @@ public class ProductSupplierDialogController { txtCost.setText(productSupplier.getCost() + ""); } - //Get the right combobox selection (product) - for (Product product : cbProduct.getItems()) { - if(product.getProdId() == productSupplier.getProdId()){ + for (DropdownOption product : cbProduct.getItems()) { + if(product.getId() == productSupplier.getProdId()){ cbProduct.getSelectionModel().select(product); } } - //Get the right combobox selection (supplier) - for (Supplier supplier : cbSupplier.getItems()) { - if (supplier.getSupId() == productSupplier.getSupId()) { + for (DropdownOption supplier : cbSupplier.getItems()) { + if (supplier.getId() == productSupplier.getSupId()) { cbSupplier.getSelectionModel().select(supplier); } } - } /** @@ -260,6 +258,7 @@ public class ProductSupplierDialogController { public void setSelectedIds(int supId, int prodId){ this.selectedSupId = supId; this.selectedProdId = prodId; + this.selectedId = (long) supId; } } diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/RefundDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/RefundDialogController.java index 85ebfc6d..2ec52b78 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/RefundDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/RefundDialogController.java @@ -7,15 +7,19 @@ import javafx.fxml.FXML; import javafx.scene.control.*; import javafx.scene.control.cell.PropertyValueFactory; import javafx.stage.Stage; +import org.example.petshopdesktop.api.dto.sale.SaleItemRequest; +import org.example.petshopdesktop.api.dto.sale.SaleItemResponse; +import org.example.petshopdesktop.api.dto.sale.SaleRequest; +import org.example.petshopdesktop.api.dto.sale.SaleResponse; +import org.example.petshopdesktop.api.endpoints.SaleApi; import org.example.petshopdesktop.auth.UserSession; -import org.example.petshopdesktop.database.SaleDB; -import org.example.petshopdesktop.models.SaleCartItem; -import org.example.petshopdesktop.models.SaleDetail; import org.example.petshopdesktop.util.ActivityLogger; -import java.sql.SQLException; +import java.math.BigDecimal; import java.text.NumberFormat; import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; import java.util.Optional; @@ -31,19 +35,19 @@ public class RefundDialogController { private Label lblSaleInfo; @FXML - private TableView tvOriginalItems; + private TableView tvOriginalItems; @FXML - private TableColumn colOriginalProduct; + private TableColumn colOriginalProduct; @FXML - private TableColumn colOriginalQuantity; + private TableColumn colOriginalQuantity; @FXML - private TableColumn colOriginalUnitPrice; + private TableColumn colOriginalUnitPrice; @FXML - private TableColumn colOriginalTotal; + private TableColumn colOriginalTotal; @FXML private Button btnAddToRefund; @@ -78,7 +82,7 @@ public class RefundDialogController { @FXML private Button btnCancel; - private SaleDetail currentSale; + private SaleResponse currentSale; private final ObservableList refundItems = FXCollections.observableArrayList(); private final NumberFormat currency = NumberFormat.getCurrencyInstance(Locale.CANADA); @@ -94,7 +98,7 @@ public class RefundDialogController { colOriginalProduct.setCellValueFactory(new PropertyValueFactory<>("productName")); colOriginalQuantity.setCellValueFactory(new PropertyValueFactory<>("quantity")); colOriginalUnitPrice.setCellValueFactory(new PropertyValueFactory<>("unitPrice")); - colOriginalTotal.setCellValueFactory(new PropertyValueFactory<>("total")); + colOriginalTotal.setCellValueFactory(new PropertyValueFactory<>("lineTotal")); tvOriginalItems.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); colRefundProduct.setCellValueFactory(new PropertyValueFactory<>("productName")); @@ -113,21 +117,25 @@ public class RefundDialogController { return; } - int saleId; + Long saleId; try { - saleId = Integer.parseInt(saleIdText); + saleId = Long.parseLong(saleIdText); } catch (NumberFormatException e) { showError("Load Sale", "Invalid transaction ID."); return; } try { - if (SaleDB.isRefunded(saleId)) { + List allSales = SaleApi.getInstance().listSales(0, 1000, null); + boolean alreadyRefunded = allSales.stream() + .anyMatch(s -> Boolean.TRUE.equals(s.getIsRefund()) && saleId.equals(s.getOriginalSaleId())); + + if (alreadyRefunded) { showError("Load Sale", "This sale has already been refunded."); return; } - currentSale = SaleDB.getSaleById(saleId); + currentSale = SaleApi.getInstance().getSale(saleId); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); String saleInfo = String.format("Sale Date: %s | Employee: %s | Original Total: %s | Payment: %s", @@ -137,13 +145,13 @@ public class RefundDialogController { currentSale.getPaymentMethod()); lblSaleInfo.setText(saleInfo); - tvOriginalItems.setItems(currentSale.getItems()); + tvOriginalItems.setItems(FXCollections.observableArrayList(currentSale.getItems())); cbPaymentMethod.getSelectionModel().select(currentSale.getPaymentMethod()); refundItems.clear(); updateRefundTotal(); - } catch (SQLException e) { + } catch (Exception e) { ActivityLogger.getInstance().logException("RefundDialogController.btnLoadSaleClicked", e, "Loading sale"); showError("Load Sale", e.getMessage() != null ? e.getMessage() : "Could not load sale."); } @@ -156,14 +164,14 @@ public class RefundDialogController { return; } - SaleDetail.SaleDetailItem selected = tvOriginalItems.getSelectionModel().getSelectedItem(); + SaleItemResponse selected = tvOriginalItems.getSelectionModel().getSelectedItem(); if (selected == null) { showError("Add to Refund", "Select an item from the original sale."); return; } int alreadyRefunded = refundItems.stream() - .filter(r -> r.getProdId() == selected.getProdId()) + .filter(r -> r.getProductId().equals(selected.getId())) .mapToInt(RefundItem::getQuantity) .sum(); @@ -192,7 +200,7 @@ public class RefundDialogController { } refundItems.add(new RefundItem( - selected.getProdId(), + selected.getId(), selected.getProductName(), quantity, selected.getUnitPrice() @@ -226,9 +234,9 @@ public class RefundDialogController { return; } - Integer employeeId = UserSession.getInstance().getEmployeeId(); - if (employeeId == null || employeeId <= 0) { - showError("Process Refund", "Employee is not set for this account."); + Long storeId = UserSession.getInstance().getStoreId(); + if (storeId == null || storeId <= 0) { + showError("Process Refund", "Store is not set for this account."); return; } @@ -240,7 +248,7 @@ public class RefundDialogController { Alert confirm = new Alert(Alert.AlertType.CONFIRMATION); confirm.setTitle("Confirm Refund"); - confirm.setHeaderText("Process refund for sale ID " + currentSale.getSaleId() + "?"); + confirm.setHeaderText("Process refund for sale ID " + currentSale.getId() + "?"); confirm.setContentText("Refund amount: " + lblRefundTotal.getText()); Optional confirmResult = confirm.showAndWait(); @@ -249,22 +257,33 @@ public class RefundDialogController { } try { - ObservableList cartItems = FXCollections.observableArrayList(); - for (RefundItem item : refundItems) { - cartItems.add(new SaleCartItem(item.getProdId(), item.getProductName(), item.getQuantity(), item.getUnitPrice())); - } + SaleRequest request = new SaleRequest(); + request.setStoreId(storeId); + request.setPaymentMethod(payment); + request.setIsRefund(true); + request.setOriginalSaleId(currentSale.getId()); - int refundId = SaleDB.createRefund(currentSale.getSaleId(), employeeId, payment, cartItems); + List items = new ArrayList<>(); + for (RefundItem item : refundItems) { + SaleItemRequest saleItem = new SaleItemRequest(); + saleItem.setProductId(item.getProductId()); + saleItem.setQuantity(-item.getQuantity()); + saleItem.setUnitPrice(item.getUnitPrice()); + items.add(saleItem); + } + request.setItems(items); + + SaleResponse refundResponse = SaleApi.getInstance().createSale(request); Alert success = new Alert(Alert.AlertType.INFORMATION); success.setTitle("Refund Processed"); success.setHeaderText(null); - success.setContentText("Refund ID " + refundId + " was created successfully."); + success.setContentText("Refund ID " + refundResponse.getId() + " was created successfully."); success.showAndWait(); closeDialog(); - } catch (SQLException e) { + } catch (Exception e) { ActivityLogger.getInstance().logException("RefundDialogController.btnProcessRefundClicked", e, "Processing refund"); showError("Process Refund", e.getMessage() != null ? e.getMessage() : "Could not process refund."); } diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ServiceDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ServiceDialogController.java index 8bc80252..5b067c16 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ServiceDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ServiceDialogController.java @@ -1,18 +1,19 @@ package org.example.petshopdesktop.controllers.dialogcontrollers; - +import javafx.application.Platform; import javafx.fxml.FXML; -import javafx.scene.Node; +import javafx.scene.control.Alert; import javafx.scene.control.Button; +import javafx.scene.control.ComboBox; import javafx.scene.control.Label; import javafx.scene.control.TextField; -import javafx.scene.input.MouseEvent; import javafx.stage.Stage; -import org.example.petshopdesktop.database.ServiceDB; -import org.example.petshopdesktop.models.Service; +import org.example.petshopdesktop.DTOs.ServiceDTO; +import org.example.petshopdesktop.api.dto.service.ServiceRequest; +import org.example.petshopdesktop.api.endpoints.ServiceApi; import org.example.petshopdesktop.util.ActivityLogger; -import javafx.scene.control.Alert; -import javafx.scene.control.ComboBox; + +import java.math.BigDecimal; public class ServiceDialogController { @@ -45,7 +46,7 @@ public class ServiceDialogController { private ComboBox cbMinutes; private String mode; - private Service selectedService; + private ServiceDTO selectedService; @@ -68,7 +69,7 @@ public class ServiceDialogController { } } - public void setService(Service service) { + public void setService(ServiceDTO service) { this.selectedService = service; lblServiceId.setText("ID: " + service.getServiceId()); diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/StaffRegisterDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/StaffRegisterDialogController.java index 2c3bd479..5f9a4a59 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/StaffRegisterDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/StaffRegisterDialogController.java @@ -1,5 +1,6 @@ package org.example.petshopdesktop.controllers.dialogcontrollers; +import javafx.application.Platform; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.Alert; @@ -8,11 +9,10 @@ import javafx.scene.control.Label; import javafx.scene.control.PasswordField; import javafx.scene.control.TextField; import javafx.stage.Stage; -import org.example.petshopdesktop.database.UserDB; +import org.example.petshopdesktop.api.dto.user.UserRequest; +import org.example.petshopdesktop.api.endpoints.UserApi; import org.example.petshopdesktop.util.ActivityLogger; -import java.sql.SQLException; - public class StaffRegisterDialogController { @FXML @@ -48,8 +48,6 @@ public class StaffRegisterDialogController { String firstName = value(txtFirstName); String lastName = value(txtLastName); - String email = value(txtEmail); - String phone = value(txtPhone); String username = value(txtUsername); String password = txtPassword.getText() == null ? "" : txtPassword.getText(); String confirm = txtPasswordConfirm.getText() == null ? "" : txtPasswordConfirm.getText(); @@ -58,14 +56,6 @@ public class StaffRegisterDialogController { lblError.setText("First name and last name are required."); return; } - if (email.isBlank()) { - lblError.setText("Email is required."); - return; - } - if (phone.isBlank()) { - lblError.setText("Phone is required."); - return; - } if (username.isBlank()) { lblError.setText("Username is required."); return; @@ -79,26 +69,41 @@ public class StaffRegisterDialogController { return; } - try { - UserDB.createStaffAccount(firstName, lastName, email, phone, username, password); - Alert alert = new Alert(Alert.AlertType.INFORMATION); - alert.setTitle("Staff Account"); - alert.setHeaderText(null); - alert.setContentText("Staff account created. You can log in now."); - alert.showAndWait(); - close(); - } catch (SQLException e) { - ActivityLogger.getInstance().logException("StaffRegisterDialogController.btnCreateClicked", e, "Creating staff account"); - String msg = e.getMessage() == null ? "Could not create staff account." : e.getMessage(); - if (msg.toLowerCase().contains("duplicate") || msg.toLowerCase().contains("unique")) { - lblError.setText("Username already exists."); - } else { - lblError.setText(msg); + btnCreate.setDisable(true); + + new Thread(() -> { + try { + UserRequest request = new UserRequest(); + request.setUsername(username); + request.setPassword(password); + request.setFirstName(firstName); + request.setLastName(lastName); + request.setRole("STAFF"); + request.setActive(true); + + UserApi.getInstance().createUser(request); + + Platform.runLater(() -> { + Alert alert = new Alert(Alert.AlertType.INFORMATION); + alert.setTitle("Staff Account"); + alert.setHeaderText(null); + alert.setContentText("Staff account created. You can log in now."); + alert.showAndWait(); + close(); + }); + } catch (Exception e) { + ActivityLogger.getInstance().logException("StaffRegisterDialogController.btnCreateClicked", e, "Creating staff account"); + String msg = e.getMessage() == null ? "Could not create staff account." : e.getMessage(); + Platform.runLater(() -> { + if (msg.toLowerCase().contains("duplicate") || msg.toLowerCase().contains("unique")) { + lblError.setText("Username already exists."); + } else { + lblError.setText(msg); + } + btnCreate.setDisable(false); + }); } - } catch (RuntimeException e) { - ActivityLogger.getInstance().logException("StaffRegisterDialogController.btnCreateClicked", e, "Database connection"); - lblError.setText("Database is not connected."); - } + }).start(); } @FXML diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/SupplierDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/SupplierDialogController.java index 836b5e6c..18dab623 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/SupplierDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/SupplierDialogController.java @@ -10,12 +10,12 @@ import javafx.scene.control.TextField; import javafx.scene.input.MouseEvent; import javafx.stage.Stage; import org.example.petshopdesktop.Validator; -import org.example.petshopdesktop.database.SupplierDB; +import org.example.petshopdesktop.api.dto.supplier.SupplierRequest; +import org.example.petshopdesktop.api.dto.supplier.SupplierResponse; +import org.example.petshopdesktop.api.endpoints.SupplierApi; import org.example.petshopdesktop.models.Supplier; import org.example.petshopdesktop.util.ActivityLogger; -import java.sql.SQLException; - public class SupplierDialogController { @FXML @@ -74,7 +74,6 @@ public class SupplierDialogController { * @param mouseEvent click event for save button */ private void buttonSaveClicked(MouseEvent mouseEvent) { - int numRow = 0; //how many rows affected String errorMsg = ""; //error message for validation //Check validation (input required) @@ -95,44 +94,29 @@ public class SupplierDialogController { errorMsg += Validator.isValidPhoneNumber(txtPhone.getText(), "Phone Number"); if(errorMsg.isEmpty()){ //no validation errors detected - Supplier supplier = collectSupplier(); //get supplier info - if (mode.equals("Add")) { //add mode - try{ - numRow = SupplierDB.insertSupplier(supplier); - } catch (SQLException e) { - ActivityLogger.getInstance().logException( - "SupplierDialogController.buttonSaveClicked", - e, - "Inserting new supplier record"); - throw new RuntimeException(e); + SupplierRequest request = createSupplierRequest(); + try { + if (mode.equals("Add")) { + SupplierApi.getInstance().createSupplier(request); + } else { + Long supplierId = Long.parseLong(lblSupId.getText().split(": ")[1]); + SupplierApi.getInstance().updateSupplier(supplierId, request); } - } - else{ //edit mode - try{ - numRow = SupplierDB.updateSupplier(supplier.getSupId(),supplier); - } catch (SQLException e) { - ActivityLogger.getInstance().logException( - "SupplierDialogController.buttonSaveClicked", - e, - "Updating supplier with ID: " + supplier.getSupId()); - throw new RuntimeException(e); - } - } - //if no rows were affected then there was an error (prompt user of error) - if (numRow == 0){ - Alert alert = new Alert(Alert.AlertType.ERROR); - alert.setHeaderText("Database Operation Error"); - alert.setContentText(mode + " failed"); - alert.showAndWait(); - } - else { - //tell the user operation was successful Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setHeaderText("Saved"); alert.setContentText(mode + " succeeded"); alert.showAndWait(); closeStage(mouseEvent); + } catch (Exception e) { + ActivityLogger.getInstance().logException( + "SupplierDialogController.buttonSaveClicked", + e, + mode.equals("Add") ? "Inserting new supplier record" : "Updating supplier record"); + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Database Operation Error"); + alert.setContentText(mode + " failed: " + e.getMessage()); + alert.showAndWait(); } } else{ //Display validation errors @@ -154,26 +138,16 @@ public class SupplierDialogController { } /** - * Collect the supplier info - * @return supplier info with the id or the new supplier + * Create a supplier request from the form inputs + * @return supplier request for API call */ - private Supplier collectSupplier(){ - int supId = 0; - Supplier supplier = null; - - if(lblSupId.isVisible()){ //Edit mode - //get supplier id from lblId (split the string so we only get the int) - supId = Integer.parseInt(lblSupId.getText().split(": ")[1]); - } - supplier = new Supplier( - supId, - txtCompanyName.getText(), - txtContactFirstName.getText(), - txtContactLastName.getText(), - txtEmail.getText(), - txtPhone.getText() - ); - return supplier; + private SupplierRequest createSupplierRequest(){ + SupplierRequest request = new SupplierRequest(); + request.setSupplierName(txtCompanyName.getText()); + request.setContactPerson(txtContactFirstName.getText() + " " + txtContactLastName.getText()); + request.setEmail(txtEmail.getText()); + request.setPhone(txtPhone.getText()); + return request; } /** diff --git a/src/main/java/org/example/petshopdesktop/models/Adoption.java b/src/main/java/org/example/petshopdesktop/models/Adoption.java index d424ff72..c5c02f63 100644 --- a/src/main/java/org/example/petshopdesktop/models/Adoption.java +++ b/src/main/java/org/example/petshopdesktop/models/Adoption.java @@ -8,16 +8,17 @@ public class Adoption { private SimpleIntegerProperty adoptionId; private SimpleIntegerProperty petId; private SimpleIntegerProperty customerId; + private SimpleStringProperty petName; private SimpleStringProperty customerName; private SimpleStringProperty adoptionDate; private SimpleDoubleProperty adoptionFee; private SimpleStringProperty adoptionStatus; - //Constructor - public Adoption(int adoptionId, int petId, int customerId, String customerName, String adoptionDate, double adoptionFee, String adoptionStatus) { + public Adoption(int adoptionId, int petId, int customerId, String petName, String customerName, String adoptionDate, double adoptionFee, String adoptionStatus) { this.adoptionId = new SimpleIntegerProperty(adoptionId); this.petId = new SimpleIntegerProperty(petId); this.customerId = new SimpleIntegerProperty(customerId); + this.petName = new SimpleStringProperty(petName); this.customerName = new SimpleStringProperty(customerName); this.adoptionDate = new SimpleStringProperty(adoptionDate); this.adoptionFee = new SimpleDoubleProperty(adoptionFee); @@ -42,6 +43,12 @@ public class Adoption { public SimpleIntegerProperty customerIdProperty() { return customerId; } + public String getPetName() { return petName.get(); } + + public void setPetName(String petName) { this.petName.set(petName); } + + public SimpleStringProperty petNameProperty() { return petName; } + public String getCustomerName() { return customerName.get(); } public void setCustomerName(String customerName) { this.customerName.set(customerName); } diff --git a/src/main/java/org/example/petshopdesktop/models/Inventory.java b/src/main/java/org/example/petshopdesktop/models/Inventory.java index ce6ec5e2..53f77543 100644 --- a/src/main/java/org/example/petshopdesktop/models/Inventory.java +++ b/src/main/java/org/example/petshopdesktop/models/Inventory.java @@ -7,14 +7,21 @@ public class Inventory { private SimpleIntegerProperty inventoryId; private SimpleIntegerProperty prodId; private SimpleStringProperty prodName; + private SimpleStringProperty categoryName; + private SimpleIntegerProperty storeId; + private SimpleStringProperty storeName; private SimpleIntegerProperty quantity; + private SimpleIntegerProperty reorderLevel; - //Constructor - public Inventory(int inventoryId, int prodId, String prodName, int quantity) { + public Inventory(int inventoryId, int prodId, String prodName, String categoryName, int storeId, String storeName, int quantity, int reorderLevel) { this.inventoryId = new SimpleIntegerProperty(inventoryId); this.prodId = new SimpleIntegerProperty(prodId); this.prodName = new SimpleStringProperty(prodName); + this.categoryName = new SimpleStringProperty(categoryName); + this.storeId = new SimpleIntegerProperty(storeId); + this.storeName = new SimpleStringProperty(storeName); this.quantity = new SimpleIntegerProperty(quantity); + this.reorderLevel = new SimpleIntegerProperty(reorderLevel); } public int getInventoryId() { return inventoryId.get(); } @@ -35,9 +42,33 @@ public class Inventory { public SimpleStringProperty prodNameProperty() { return prodName; } + public String getCategoryName() { return categoryName.get(); } + + public void setCategoryName(String categoryName) { this.categoryName.set(categoryName); } + + public SimpleStringProperty categoryNameProperty() { return categoryName; } + + public int getStoreId() { return storeId.get(); } + + public void setStoreId(int storeId) { this.storeId.set(storeId); } + + public SimpleIntegerProperty storeIdProperty() { return storeId; } + + public String getStoreName() { return storeName.get(); } + + public void setStoreName(String storeName) { this.storeName.set(storeName); } + + public SimpleStringProperty storeNameProperty() { return storeName; } + public int getQuantity() { return quantity.get(); } public void setQuantity(int quantity) { this.quantity.set(quantity); } public SimpleIntegerProperty quantityProperty() { return quantity; } + + public int getReorderLevel() { return reorderLevel.get(); } + + public void setReorderLevel(int reorderLevel) { this.reorderLevel.set(reorderLevel); } + + public SimpleIntegerProperty reorderLevelProperty() { return reorderLevel; } } diff --git a/src/main/java/org/example/petshopdesktop/models/PurchaseOrder.java b/src/main/java/org/example/petshopdesktop/models/PurchaseOrder.java index 3b1cf838..c13afe50 100644 --- a/src/main/java/org/example/petshopdesktop/models/PurchaseOrder.java +++ b/src/main/java/org/example/petshopdesktop/models/PurchaseOrder.java @@ -1,35 +1,52 @@ package org.example.petshopdesktop.models; +import java.math.BigDecimal; +import java.time.LocalDate; + public class PurchaseOrder { - private int purchaseOrderId; - private int supId; - private String orderDate; + private long purchaseOrderId; + private String supplierName; + private LocalDate orderDate; + private LocalDate expectedDeliveryDate; private String status; + private BigDecimal totalAmount; - public PurchaseOrder(int purchaseOrderId, - int supId, - String orderDate, - String status) { + public PurchaseOrder(long purchaseOrderId, + String supplierName, + LocalDate orderDate, + LocalDate expectedDeliveryDate, + String status, + BigDecimal totalAmount) { this.purchaseOrderId = purchaseOrderId; - this.supId = supId; + this.supplierName = supplierName; this.orderDate = orderDate; + this.expectedDeliveryDate = expectedDeliveryDate; this.status = status; + this.totalAmount = totalAmount; } - public int getPurchaseOrderId() { + public long getPurchaseOrderId() { return purchaseOrderId; } - public int getSupId() { - return supId; + public String getSupplierName() { + return supplierName; } - public String getOrderDate() { + public LocalDate getOrderDate() { return orderDate; } + public LocalDate getExpectedDeliveryDate() { + return expectedDeliveryDate; + } + public String getStatus() { return status; } + + public BigDecimal getTotalAmount() { + return totalAmount; + } } \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/models/StaffAccount.java b/src/main/java/org/example/petshopdesktop/models/StaffAccount.java index c17d0472..e1b0ab62 100644 --- a/src/main/java/org/example/petshopdesktop/models/StaffAccount.java +++ b/src/main/java/org/example/petshopdesktop/models/StaffAccount.java @@ -3,8 +3,8 @@ package org.example.petshopdesktop.models; import java.sql.Timestamp; public class StaffAccount { - private final int userId; - private final int employeeId; + private final long userId; + private final long employeeId; private final String username; private final String firstName; private final String lastName; @@ -13,7 +13,7 @@ public class StaffAccount { private final boolean active; private final Timestamp createdAt; - public StaffAccount(int userId, int employeeId, String username, String firstName, String lastName, String email, String phone, boolean active, Timestamp createdAt) { + public StaffAccount(long userId, long employeeId, String username, String firstName, String lastName, String email, String phone, boolean active, Timestamp createdAt) { this.userId = userId; this.employeeId = employeeId; this.username = username; @@ -25,11 +25,11 @@ public class StaffAccount { this.createdAt = createdAt; } - public int getUserId() { + public long getUserId() { return userId; } - public int getEmployeeId() { + public long getEmployeeId() { return employeeId; } From 8f88cc41a83c7fe4f8730df4a0c44baf458b6aae Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Sat, 7 Mar 2026 17:04:24 -0700 Subject: [PATCH 06/19] Complete InventoryDialogController migration --- .../InventoryDialogController.java | 135 ++++++------------ 1 file changed, 44 insertions(+), 91 deletions(-) diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/InventoryDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/InventoryDialogController.java index b058bf2a..85cca148 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/InventoryDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/InventoryDialogController.java @@ -1,5 +1,7 @@ package org.example.petshopdesktop.controllers.dialogcontrollers; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.scene.Node; @@ -11,14 +13,19 @@ import javafx.scene.control.TextField; import javafx.scene.input.MouseEvent; import javafx.stage.Stage; import javafx.util.StringConverter; +import org.example.petshopdesktop.DTOs.InventoryDTO; import org.example.petshopdesktop.Validator; -import org.example.petshopdesktop.database.InventoryDB; -import org.example.petshopdesktop.database.ProductDB; -import org.example.petshopdesktop.models.Inventory; +import org.example.petshopdesktop.api.dto.inventory.InventoryRequest; +import org.example.petshopdesktop.api.dto.inventory.InventoryResponse; +import org.example.petshopdesktop.api.dto.product.ProductResponse; +import org.example.petshopdesktop.api.endpoints.InventoryApi; +import org.example.petshopdesktop.api.endpoints.ProductApi; import org.example.petshopdesktop.models.Product; import org.example.petshopdesktop.util.ActivityLogger; -import java.sql.SQLException; +import java.math.BigDecimal; +import java.util.List; +import java.util.stream.Collectors; public class InventoryDialogController { @@ -60,12 +67,21 @@ public class InventoryDialogController { public Product fromString(String string) { return null; } }); - //Load product list from DB into combobox + //Load product list from API into combobox try { - cbProduct.setItems(ProductDB.getProducts()); - } - - catch (SQLException e) { + List productResponses = ProductApi.getInstance().listProducts(null); + ObservableList products = FXCollections.observableArrayList(); + for (ProductResponse pr : productResponses) { + products.add(new Product( + pr.getId().intValue(), + pr.getProductName(), + pr.getPrice().doubleValue(), + 0, + pr.getDescription() + )); + } + cbProduct.setItems(products); + } catch (Exception e) { ActivityLogger.getInstance().logException( "InventoryDialogController.initialize", e, @@ -106,75 +122,33 @@ public class InventoryDialogController { //Operation only occurs if there are no errors if (errorMsg.isEmpty()) { - - //Ensures duplicate entries aren't possible - if (mode.equals("Add")) { + try { + InventoryRequest request = new InventoryRequest(); Product selectedProduct = cbProduct.getSelectionModel().getSelectedItem(); + request.setProductId((long) selectedProduct.getProdId()); + request.setQuantity(Integer.parseInt(txtQuantity.getText())); - try { - - if (InventoryDB.productExistsInInventory(selectedProduct.getProdId())) { - Alert alert = new Alert(Alert.AlertType.ERROR); - alert.setHeaderText("Duplicate Entry"); - alert.setContentText("An inventory record for \"" + selectedProduct.getProdName() + "\" already exists."); - alert.showAndWait(); - return; - } + if (mode.equals("Add")) { + InventoryApi.getInstance().createInventory(request); + } else { + Long inventoryId = Long.parseLong(lblInventoryId.getText().split(": ")[1]); + InventoryApi.getInstance().updateInventory(inventoryId, request); } - catch (SQLException e) { - ActivityLogger.getInstance().logException( - "InventoryDialogController.buttonSaveClicked", - e, - "Checking if product exists in inventory"); - throw new RuntimeException(e); - } - } - - Inventory inventory = collectInventory(); - - //Adding inventory - if (mode.equals("Add")) { - try { - numRow = InventoryDB.insertInventory(inventory); - } catch (SQLException e) { - ActivityLogger.getInstance().logException( - "InventoryDialogController.buttonSaveClicked", - e, - "Inserting new inventory record"); - throw new RuntimeException(e); - } - } - - //Updating inventory - else { - try { - numRow = InventoryDB.updateInventory(inventory.getInventoryId(), inventory); - } - - catch (SQLException e) { - ActivityLogger.getInstance().logException( - "InventoryDialogController.buttonSaveClicked", - e, - "Updating inventory with ID: " + inventory.getInventoryId()); - throw new RuntimeException(e); - } - } - - //Display database operation result - if (numRow == 0) { - Alert alert = new Alert(Alert.AlertType.ERROR); - alert.setHeaderText("Database Operation Error"); - alert.setContentText(mode + " failed"); - alert.showAndWait(); - } - - else { Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setHeaderText("Saved"); alert.setContentText(mode + " succeeded"); alert.showAndWait(); closeStage(mouseEvent); + } catch (Exception e) { + ActivityLogger.getInstance().logException( + "InventoryDialogController.buttonSaveClicked", + e, + mode + " inventory"); + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.setHeaderText("Database Operation Error"); + alert.setContentText(e.getMessage()); + alert.showAndWait(); } } @@ -187,27 +161,6 @@ public class InventoryDialogController { } } - //Create Inventory object using values entered by user - private Inventory collectInventory() { - int inventoryId = 0; - - //Grab inventory ID when editing pre-existing record - if (lblInventoryId.isVisible()) { - inventoryId = Integer.parseInt(lblInventoryId.getText().split(": ")[1]); - } - - //Get selected product - Product selectedProduct = cbProduct.getSelectionModel().getSelectedItem(); - - //Build and returns Inventory object - return new Inventory( - inventoryId, - selectedProduct.getProdId(), - selectedProduct.getProdName(), - Integer.parseInt(txtQuantity.getText()) - ); - } - //Close dialog view private void closeStage(MouseEvent mouseEvent) { Node node = (Node) mouseEvent.getSource(); @@ -217,7 +170,7 @@ public class InventoryDialogController { //Editing //Displays fields with existing inventory data - public void displayInventoryDetails(Inventory inventory) { + public void displayInventoryDetails(InventoryDTO inventory) { if (inventory != null) { //Displays inventory ID From 0e8ec35995bdc45a0a3f122c077d34e448a23f43 Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Sat, 7 Mar 2026 17:04:46 -0700 Subject: [PATCH 07/19] Remove mysql-connector-j dependency --- pom.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pom.xml b/pom.xml index 437e7605..aaf1168e 100644 --- a/pom.xml +++ b/pom.xml @@ -39,12 +39,6 @@ test - - com.mysql - mysql-connector-j - 9.3.0 - - com.fasterxml.jackson.core jackson-databind From a6e424de4179c6ed2e37cb95f7205418c8bab7d1 Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Sat, 7 Mar 2026 17:07:43 -0700 Subject: [PATCH 08/19] Fix compilation errors in controllers --- .../controllers/AnalyticsController.java | 15 +++++++++++---- .../controllers/SaleController.java | 3 +-- .../InventoryDialogController.java | 6 +++--- .../RefundDialogController.java | 10 +++++----- .../ServiceDialogController.java | 19 +++++++------------ .../petshopdesktop/database/AdoptionDB.java | 1 + .../petshopdesktop/database/InventoryDB.java | 6 +++++- 7 files changed, 33 insertions(+), 27 deletions(-) diff --git a/src/main/java/org/example/petshopdesktop/controllers/AnalyticsController.java b/src/main/java/org/example/petshopdesktop/controllers/AnalyticsController.java index b0637ab0..0349197f 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/AnalyticsController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/AnalyticsController.java @@ -196,13 +196,20 @@ public class AnalyticsController { chartPaymentMethods.setLabelsVisible(false); } - private void loadEmployeePerformance() throws Exception { - ObservableList data = SaleDB.getEmployeeSalesPerformance(); + private void loadEmployeePerformance(List sales) throws Exception { + Map employeeRevenue = sales.stream() + .filter(sale -> sale.getIsRefund() == null || !sale.getIsRefund()) + .filter(sale -> sale.getEmployeeName() != null) + .collect(Collectors.groupingBy( + SaleResponse::getEmployeeName, + Collectors.summingDouble(sale -> sale.getTotalAmount() != null ? sale.getTotalAmount().doubleValue() : 0.0) + )); + XYChart.Series series = new XYChart.Series<>(); series.setName("Revenue"); - for (EmployeeSalesData employee : data) { - series.getData().add(new XYChart.Data<>(employee.getEmployeeName(), employee.getTotalRevenue())); + for (Map.Entry entry : employeeRevenue.entrySet()) { + series.getData().add(new XYChart.Data<>(entry.getKey(), entry.getValue())); } chartEmployeePerformance.getData().clear(); diff --git a/src/main/java/org/example/petshopdesktop/controllers/SaleController.java b/src/main/java/org/example/petshopdesktop/controllers/SaleController.java index 0e2041a2..d22e3f86 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/SaleController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/SaleController.java @@ -240,7 +240,7 @@ public class SaleController { task.setOnFailed(event -> { Throwable e = task.getException(); - ActivityLogger.getInstance().logException("SaleController.refreshSales", e, "Loading sales"); + ActivityLogger.getInstance().logException("SaleController.refreshSales", (Exception) e, "Loading sales"); if (showErrorDialog) { showError("Sales", "Could not load sales: " + e.getMessage()); } @@ -376,7 +376,6 @@ public class SaleController { dialog.setResizable(false); dialog.showAndWait(); - refreshInventory(); refreshSales(true); } catch (Exception e) { ActivityLogger.getInstance().logException("SaleController.openRefundDialog", e, "Opening refund dialog"); diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/InventoryDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/InventoryDialogController.java index 85cca148..fd594c18 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/InventoryDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/InventoryDialogController.java @@ -13,7 +13,7 @@ import javafx.scene.control.TextField; import javafx.scene.input.MouseEvent; import javafx.stage.Stage; import javafx.util.StringConverter; -import org.example.petshopdesktop.DTOs.InventoryDTO; +import org.example.petshopdesktop.models.Inventory; import org.example.petshopdesktop.Validator; import org.example.petshopdesktop.api.dto.inventory.InventoryRequest; import org.example.petshopdesktop.api.dto.inventory.InventoryResponse; @@ -126,7 +126,7 @@ public class InventoryDialogController { InventoryRequest request = new InventoryRequest(); Product selectedProduct = cbProduct.getSelectionModel().getSelectedItem(); request.setProductId((long) selectedProduct.getProdId()); - request.setQuantity(Integer.parseInt(txtQuantity.getText())); + request.setStockQuantity(Integer.parseInt(txtQuantity.getText())); if (mode.equals("Add")) { InventoryApi.getInstance().createInventory(request); @@ -170,7 +170,7 @@ public class InventoryDialogController { //Editing //Displays fields with existing inventory data - public void displayInventoryDetails(InventoryDTO inventory) { + public void displayInventoryDetails(Inventory inventory) { if (inventory != null) { //Displays inventory ID diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/RefundDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/RefundDialogController.java index 2ec52b78..0343b27b 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/RefundDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/RefundDialogController.java @@ -171,7 +171,7 @@ public class RefundDialogController { } int alreadyRefunded = refundItems.stream() - .filter(r -> r.getProductId().equals(selected.getId())) + .filter(r -> r.getProdId() == selected.getId().intValue()) .mapToInt(RefundItem::getQuantity) .sum(); @@ -200,10 +200,10 @@ public class RefundDialogController { } refundItems.add(new RefundItem( - selected.getId(), + selected.getId().intValue(), selected.getProductName(), quantity, - selected.getUnitPrice() + selected.getUnitPrice().doubleValue() )); updateRefundTotal(); @@ -266,9 +266,9 @@ public class RefundDialogController { List items = new ArrayList<>(); for (RefundItem item : refundItems) { SaleItemRequest saleItem = new SaleItemRequest(); - saleItem.setProductId(item.getProductId()); + saleItem.setProductId((long) item.getProdId()); saleItem.setQuantity(-item.getQuantity()); - saleItem.setUnitPrice(item.getUnitPrice()); + saleItem.setUnitPrice(BigDecimal.valueOf(item.getUnitPrice())); items.add(saleItem); } request.setItems(items); diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ServiceDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ServiceDialogController.java index 5b067c16..8e61169f 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ServiceDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ServiceDialogController.java @@ -115,22 +115,17 @@ public class ServiceDialogController { return; } - int duration = (hours * 60) + minutes; - - Service service = new Service( - selectedService == null ? 0 : selectedService.getServiceId(), - name, - desc, - duration, - price - ); - try { + ServiceRequest request = new ServiceRequest(); + request.setServiceName(name); + request.setDescription(desc); + request.setPrice(BigDecimal.valueOf(price)); if (mode.equals("Add")) { - ServiceDB.insertService(service); + ServiceApi.getInstance().createService(request); } else { - ServiceDB.updateService(selectedService.getServiceId(), service); + Long serviceId = (long) selectedService.getServiceId(); + ServiceApi.getInstance().updateService(serviceId, request); } close(); diff --git a/src/main/java/org/example/petshopdesktop/database/AdoptionDB.java b/src/main/java/org/example/petshopdesktop/database/AdoptionDB.java index 40efa4d2..dee46805 100644 --- a/src/main/java/org/example/petshopdesktop/database/AdoptionDB.java +++ b/src/main/java/org/example/petshopdesktop/database/AdoptionDB.java @@ -156,6 +156,7 @@ public class AdoptionDB { rs.getInt("adoptionId"), rs.getInt("petId"), rs.getInt("customerId"), + "", rs.getString("customerName"), rs.getString("adoptionDate"), rs.getDouble("adoptionFee"), diff --git a/src/main/java/org/example/petshopdesktop/database/InventoryDB.java b/src/main/java/org/example/petshopdesktop/database/InventoryDB.java index e0361321..792f9e6d 100644 --- a/src/main/java/org/example/petshopdesktop/database/InventoryDB.java +++ b/src/main/java/org/example/petshopdesktop/database/InventoryDB.java @@ -152,7 +152,11 @@ public class InventoryDB { rs.getInt("inventoryId"), rs.getInt("prodId"), rs.getString("prodName"), - rs.getInt("quantity") + "", + 0, + "", + rs.getInt("quantity"), + 0 ); } } \ No newline at end of file From b5084c6d2e989d8ba95763059dbaa95c22a811d7 Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Sat, 7 Mar 2026 17:45:12 -0700 Subject: [PATCH 09/19] Remove database package and references --- connectionpetstore.properties | 5 +- .../petshopdesktop/PetShopApplication.java | 6 - .../petshopdesktop/database/AdoptionDB.java | 166 ----- .../database/AppointmentDB.java | 223 ------- .../petshopdesktop/database/CategoryDB.java | 41 -- .../petshopdesktop/database/ConnectionDB.java | 66 -- .../petshopdesktop/database/CustomerDB.java | 43 -- .../petshopdesktop/database/EmployeeDB.java | 132 ---- .../petshopdesktop/database/InventoryDB.java | 162 ----- .../petshopdesktop/database/PetDB.java | 167 ----- .../petshopdesktop/database/ProductDB.java | 234 ------- .../database/ProductSupplierDB.java | 219 ------- .../database/PurchaseOrderDB.java | 45 -- .../petshopdesktop/database/SaleDB.java | 572 ------------------ .../petshopdesktop/database/ServiceDB.java | 129 ---- .../petshopdesktop/database/SupplierDB.java | 202 ------- .../petshopdesktop/database/UserDB.java | 198 ------ 17 files changed, 1 insertion(+), 2609 deletions(-) delete mode 100644 src/main/java/org/example/petshopdesktop/database/AdoptionDB.java delete mode 100644 src/main/java/org/example/petshopdesktop/database/AppointmentDB.java delete mode 100644 src/main/java/org/example/petshopdesktop/database/CategoryDB.java delete mode 100644 src/main/java/org/example/petshopdesktop/database/ConnectionDB.java delete mode 100644 src/main/java/org/example/petshopdesktop/database/CustomerDB.java delete mode 100644 src/main/java/org/example/petshopdesktop/database/EmployeeDB.java delete mode 100644 src/main/java/org/example/petshopdesktop/database/InventoryDB.java delete mode 100644 src/main/java/org/example/petshopdesktop/database/PetDB.java delete mode 100644 src/main/java/org/example/petshopdesktop/database/ProductDB.java delete mode 100644 src/main/java/org/example/petshopdesktop/database/ProductSupplierDB.java delete mode 100644 src/main/java/org/example/petshopdesktop/database/PurchaseOrderDB.java delete mode 100644 src/main/java/org/example/petshopdesktop/database/SaleDB.java delete mode 100644 src/main/java/org/example/petshopdesktop/database/ServiceDB.java delete mode 100644 src/main/java/org/example/petshopdesktop/database/SupplierDB.java delete mode 100644 src/main/java/org/example/petshopdesktop/database/UserDB.java diff --git a/connectionpetstore.properties b/connectionpetstore.properties index 00ffda7d..bdee2f8d 100644 --- a/connectionpetstore.properties +++ b/connectionpetstore.properties @@ -1,4 +1 @@ -url=jdbc:mysql://127.0.0.1:3306/Petstoredb?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC -user=petapp -password=petapppass -api.baseUrl=http://localhost:8080 \ No newline at end of file +api.baseUrl=http://localhost:8080 diff --git a/src/main/java/org/example/petshopdesktop/PetShopApplication.java b/src/main/java/org/example/petshopdesktop/PetShopApplication.java index 06def37b..0127e42c 100644 --- a/src/main/java/org/example/petshopdesktop/PetShopApplication.java +++ b/src/main/java/org/example/petshopdesktop/PetShopApplication.java @@ -4,18 +4,12 @@ import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; import javafx.stage.Stage; -import org.example.petshopdesktop.database.UserDB; import java.io.IOException; public class PetShopApplication extends Application { @Override public void start(Stage stage) throws IOException { - try { - UserDB.initializeTable(); - } catch (Exception e) { - System.err.println("Warning: could not initialize users table: " + e.getMessage()); - } FXMLLoader fxmlLoader = new FXMLLoader(PetShopApplication.class.getResource("login-view.fxml")); Scene scene = new Scene(fxmlLoader.load()); stage.setTitle("Pet Shop Manager - Login"); diff --git a/src/main/java/org/example/petshopdesktop/database/AdoptionDB.java b/src/main/java/org/example/petshopdesktop/database/AdoptionDB.java deleted file mode 100644 index dee46805..00000000 --- a/src/main/java/org/example/petshopdesktop/database/AdoptionDB.java +++ /dev/null @@ -1,166 +0,0 @@ -package org.example.petshopdesktop.database; - -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import org.example.petshopdesktop.models.Adoption; -import org.example.petshopdesktop.models.Customer; -import org.example.petshopdesktop.models.Pet; -import org.example.petshopdesktop.util.ActivityLogger; - -import java.sql.*; - -public class AdoptionDB { - - //Select query - private static final String BASE_SELECT = - "SELECT a.adoptionId, a.petId, a.customerId, " + - "CONCAT(c.firstName, ' ', c.lastName) AS customerName, " + - "a.adoptionDate, p.petPrice AS adoptionFee, a.adoptionStatus " + - "FROM adoption a " + - "JOIN customer c ON a.customerId = c.customerId " + - "JOIN pet p ON a.petId = p.petId"; - - //Retrieve all adoption records from DB - public static ObservableList getAdoptions() throws SQLException { - ObservableList adoptions = FXCollections.observableArrayList(); - Connection conn = ConnectionDB.getConnection(); - - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(BASE_SELECT); - - //Map results - while (rs.next()) { - adoptions.add(mapRow(rs)); - } - - conn.close(); - return adoptions; - } - - //Returns data depending on search query - public static ObservableList getFilteredAdoptions(String filter) throws SQLException { - ObservableList adoptions = FXCollections.observableArrayList(); - Connection conn = ConnectionDB.getConnection(); - - String sql = BASE_SELECT + - " WHERE a.adoptionId LIKE '%" + filter + "%' OR " + - "a.petId LIKE '%" + filter + "%' OR " + - "CONCAT(c.firstName, ' ', c.lastName) LIKE '%" + filter + "%' OR " + - "a.adoptionDate LIKE '%" + filter + "%' OR " + - "p.petPrice LIKE '%" + filter + "%' OR " + - "a.adoptionStatus LIKE '%" + filter + "%'"; - - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(sql); - - //Map results - while (rs.next()) { - adoptions.add(mapRow(rs)); - } - - conn.close(); - return adoptions; - } - - //Add new adoption - public static int insertAdoption(Adoption adoption) throws SQLException { - Connection conn = ConnectionDB.getConnection(); - String sql = "INSERT INTO adoption (petId, customerId, adoptionDate, adoptionStatus) VALUES (?, ?, ?, ?)"; - - PreparedStatement stmt = conn.prepareStatement(sql); - - //Put data in Adoption object - stmt.setInt(1, adoption.getPetId()); - stmt.setInt(2, adoption.getCustomerId()); - stmt.setString(3, adoption.getAdoptionDate()); - stmt.setString(4, adoption.getAdoptionStatus()); - - int numRows = stmt.executeUpdate(); - conn.close(); - - // Log the operation - if (numRows > 0) { - ActivityLogger.getInstance().logInsert("adoption", - "N/A", - String.format("Adoption record added for Pet ID %d, Customer ID %d", adoption.getPetId(), adoption.getCustomerId())); - } - - return numRows; - } - - //Updating pre-existing adoption - public static int updateAdoption(int adoptionId, Adoption adoption) throws SQLException { - Connection conn = ConnectionDB.getConnection(); - String sql = "UPDATE adoption SET petId = ?, customerId = ?, adoptionDate = ?, adoptionStatus = ? WHERE adoptionId = ?"; - - PreparedStatement stmt = conn.prepareStatement(sql); - stmt.setInt(1, adoption.getPetId()); - stmt.setInt(2, adoption.getCustomerId()); - stmt.setString(3, adoption.getAdoptionDate()); - stmt.setString(4, adoption.getAdoptionStatus()); - stmt.setInt(5, adoptionId); - - int numRows = stmt.executeUpdate(); - conn.close(); - - // Log the operation - if (numRows > 0) { - ActivityLogger.getInstance().logUpdate("adoption", - String.valueOf(adoptionId), - String.format("Adoption ID %d updated", adoptionId)); - } - - return numRows; - } - - //Delete adoption - public static int deleteAdoption(int adoptionId) throws SQLException { - Connection conn = ConnectionDB.getConnection(); - String sql = "DELETE FROM adoption WHERE adoptionId = ?"; - - PreparedStatement stmt = conn.prepareStatement(sql); - stmt.setInt(1, adoptionId); - - int numRows = stmt.executeUpdate(); - conn.close(); - - // Log the operation - if (numRows > 0) { - ActivityLogger.getInstance().logDelete("adoption", - String.valueOf(adoptionId), - String.format("Adoption ID %d deleted", adoptionId)); - } - - return numRows; - } - - //Grab list of customers from DB for comboboxes - public static ObservableList getCustomers() throws SQLException { - ObservableList customers = FXCollections.observableArrayList(); - Connection conn = ConnectionDB.getConnection(); - - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT customerId, firstName, lastName, email, phone FROM customer"); - - while (rs.next()) { - customers.add(new Customer(rs.getInt(1), rs.getString(2), rs.getString(3), rs.getString(4), rs.getString(5))); - } - - conn.close(); - return customers; - } - - //DRY: converts DB data into usable Java object - private static Adoption mapRow(ResultSet rs) throws SQLException { - return new Adoption( - rs.getInt("adoptionId"), - rs.getInt("petId"), - rs.getInt("customerId"), - "", - rs.getString("customerName"), - rs.getString("adoptionDate"), - rs.getDouble("adoptionFee"), - rs.getString("adoptionStatus") - ); - } -} diff --git a/src/main/java/org/example/petshopdesktop/database/AppointmentDB.java b/src/main/java/org/example/petshopdesktop/database/AppointmentDB.java deleted file mode 100644 index 747dd0f3..00000000 --- a/src/main/java/org/example/petshopdesktop/database/AppointmentDB.java +++ /dev/null @@ -1,223 +0,0 @@ -package org.example.petshopdesktop.database; - -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; - -import org.example.petshopdesktop.DTOs.AppointmentDTO; -import org.example.petshopdesktop.models.Appointment; -import org.example.petshopdesktop.util.ActivityLogger; - -import java.sql.*; - -public class AppointmentDB { - - // ============================ - // GET ALL APPOINTMENTS - // ============================ - public static ObservableList getAppointmentDTOs() - throws SQLException { - - ObservableList list = - FXCollections.observableArrayList(); - - Connection conn = ConnectionDB.getConnection(); - - String sql = """ - SELECT a.appointmentId, - c.customerId, - CONCAT(c.firstName,' ',c.lastName) AS customerName, - p.petId, - p.petName, - s.serviceId, - s.serviceName, - a.appointmentDate, - a.appointmentTime, - a.appointmentStatus - FROM appointment a - JOIN customer c ON a.customerId = c.customerId - JOIN appointmentPet ap ON a.appointmentId = ap.appointmentId - JOIN pet p ON ap.petId = p.petId - JOIN service s ON a.serviceId = s.serviceId - """; - - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(sql); - - while (rs.next()) { - - AppointmentDTO dto = new AppointmentDTO( - rs.getInt("appointmentId"), - - rs.getInt("customerId"), - rs.getString("customerName"), - - rs.getInt("petId"), - rs.getString("petName"), - - rs.getInt("serviceId"), - rs.getString("serviceName"), - - rs.getString("appointmentDate"), - rs.getString("appointmentTime"), - rs.getString("appointmentStatus") - ); - - list.add(dto); - } - - conn.close(); - return list; - } - - // ============================ - // INSERT APPOINTMENT - // ============================ - public static int insertAppointment(Appointment appt) - throws SQLException { - - Connection conn = ConnectionDB.getConnection(); - - String sql = """ - INSERT INTO appointment - (serviceId, customerId, appointmentDate, - appointmentTime, appointmentStatus) - VALUES (?,?,?,?,?) - """; - - PreparedStatement ps = - conn.prepareStatement(sql, - Statement.RETURN_GENERATED_KEYS); - - ps.setInt(1, appt.getServiceId()); - ps.setInt(2, appt.getCustomerId()); - ps.setString(3, appt.getAppointmentDate()); - ps.setString(4, appt.getAppointmentTime()); - ps.setString(5, appt.getAppointmentStatus()); - - ps.executeUpdate(); - - ResultSet keys = ps.getGeneratedKeys(); - int newId = 0; - - if (keys.next()) { - newId = keys.getInt(1); - } - - conn.close(); - - // Log the operation - if (newId > 0) { - ActivityLogger.getInstance().logInsert("appointment", - String.valueOf(newId), - String.format("Appointment created for Customer ID %d, Service ID %d", appt.getCustomerId(), appt.getServiceId())); - } - - return newId; - } - - // - // LINK PET TO APPOINTMENT - // - public static void insertAppointmentPet(int appointmentId, - int petId) - throws SQLException { - - Connection conn = ConnectionDB.getConnection(); - - String sql = - "INSERT INTO appointmentPet (appointmentId, petId) VALUES (?,?)"; - - PreparedStatement ps = conn.prepareStatement(sql); - ps.setInt(1, appointmentId); - ps.setInt(2, petId); - int numRows = ps.executeUpdate(); - - conn.close(); - - // Log the operation - if (numRows > 0) { - ActivityLogger.getInstance().logInsert("appointmentPet", - String.valueOf(appointmentId), - String.format("Pet ID %d linked to Appointment ID %d", petId, appointmentId)); - } - } - - // - // UPDATE APPOINTMENT - // - public static int updateAppointment(int id, - Appointment appt, - int petId) - throws SQLException { - - Connection conn = ConnectionDB.getConnection(); - - String sql = - "UPDATE appointment SET serviceId=?, customerId=?, " + - "appointmentDate=?, appointmentTime=?, appointmentStatus=? " + - "WHERE appointmentId=?"; - - PreparedStatement ps = conn.prepareStatement(sql); - - ps.setInt(1, appt.getServiceId()); - ps.setInt(2, appt.getCustomerId()); - ps.setString(3, appt.getAppointmentDate()); - ps.setString(4, appt.getAppointmentTime()); - ps.setString(5, appt.getAppointmentStatus()); - ps.setInt(6, id); - - ps.executeUpdate(); - - String sql2 = - "UPDATE appointmentPet SET petId=? WHERE appointmentId=?"; - - PreparedStatement ps2 = conn.prepareStatement(sql2); - ps2.setInt(1, petId); - ps2.setInt(2, id); - ps2.executeUpdate(); - - conn.close(); - - // Log the operation - ActivityLogger.getInstance().logUpdate("appointment", - String.valueOf(id), - String.format("Appointment ID %d updated", id)); - - return 1; - } - - // - // DELETE APPOINTMENT - // - public static int deleteAppointment(int id) - throws SQLException { - - Connection conn = ConnectionDB.getConnection(); - - PreparedStatement ps1 = - conn.prepareStatement( - "DELETE FROM appointmentPet WHERE appointmentId=?" - ); - ps1.setInt(1, id); - ps1.executeUpdate(); - - PreparedStatement ps2 = - conn.prepareStatement( - "DELETE FROM appointment WHERE appointmentId=?" - ); - ps2.setInt(1, id); - - int rows = ps2.executeUpdate(); - - conn.close(); - - // Log the operation - if (rows > 0) { - ActivityLogger.getInstance().logDelete("appointment", - String.valueOf(id), - String.format("Appointment ID %d deleted", id)); - } - - return rows; - } -} \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/database/CategoryDB.java b/src/main/java/org/example/petshopdesktop/database/CategoryDB.java deleted file mode 100644 index f9a2a434..00000000 --- a/src/main/java/org/example/petshopdesktop/database/CategoryDB.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.example.petshopdesktop.database; - -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import org.example.petshopdesktop.models.Category; -import org.example.petshopdesktop.models.Product; - -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -public class CategoryDB { - /** - * gets all the category into an observable list - * @return a list of all the category - * @throws SQLException if failed to find categories in the database - */ - public static ObservableList getCategories() throws SQLException{ - //Connect to the database - ObservableList categories = FXCollections.observableArrayList(); - Connection conn = ConnectionDB.getConnection(); - - //Execute Query - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT * FROM category"); - - //While there is still data add categories to the list - while(rs.next()){ - Category category = new Category( - rs.getInt(1), - rs.getString(2), - rs.getString(3)); - categories.add(category); - } - - //close connection and return categories - conn.close(); - return categories; - } -} diff --git a/src/main/java/org/example/petshopdesktop/database/ConnectionDB.java b/src/main/java/org/example/petshopdesktop/database/ConnectionDB.java deleted file mode 100644 index 09209c3e..00000000 --- a/src/main/java/org/example/petshopdesktop/database/ConnectionDB.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.example.petshopdesktop.database; - -import org.example.petshopdesktop.util.ActivityLogger; - -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; -import java.util.Properties; - -public class ConnectionDB { - /** - * Method to try and connect to the database using connectionpetstore.properties. - * @return Connection to the database - */ - public static Connection getConnection(){ - String url = ""; - String user = ""; - String password = ""; - - Properties prop = new Properties(); - Path propsPath; - - String explicitPath = System.getenv("PETSTORE_DB_PROPS"); - if (explicitPath != null && !explicitPath.isBlank()) { - propsPath = Paths.get(explicitPath); - } else { - Path cwd = Paths.get(System.getProperty("user.dir"), "connectionpetstore.properties"); - Path xdg = Paths.get(System.getProperty("user.home"), ".config", "petstore", "connectionpetstore.properties"); - Path legacyWindows = Paths.get("./connectionpetstore.properties"); - - if (Files.exists(cwd)) propsPath = cwd; - else if (Files.exists(xdg)) propsPath = xdg; - else propsPath = legacyWindows; - } - - try (FileInputStream fis = new FileInputStream(propsPath.toString())) { - prop.load(fis); - url = prop.getProperty("url"); - user = prop.getProperty("user"); - password = prop.getProperty("password"); - } - catch(IOException e){ - ActivityLogger.getInstance().logException( - "ConnectionDB.getConnection", - e, - "Reading connection properties file"); - throw new RuntimeException("Problem with reading connection info: "+e.getMessage()); - } - - try{ - return DriverManager.getConnection(url,user,password); - } - catch (SQLException e) { - ActivityLogger.getInstance().logException( - "ConnectionDB.getConnection", - e, - "Establishing database connection"); - throw new RuntimeException("Problem with database connection: "+e.getMessage()); - } - } -} diff --git a/src/main/java/org/example/petshopdesktop/database/CustomerDB.java b/src/main/java/org/example/petshopdesktop/database/CustomerDB.java deleted file mode 100644 index abe47004..00000000 --- a/src/main/java/org/example/petshopdesktop/database/CustomerDB.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.example.petshopdesktop.database; - -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import org.example.petshopdesktop.models.Customer; - -import java.sql.*; - -public class CustomerDB { - - // - // GET ALL CUSTOMERS - // - public static ObservableList getCustomers() - throws SQLException { - - ObservableList list = - FXCollections.observableArrayList(); - - Connection conn = ConnectionDB.getConnection(); - - String sql = "SELECT * FROM customer"; - - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(sql); - - while(rs.next()) { - - Customer c = new Customer( - rs.getInt("customerId"), - rs.getString("firstName"), - rs.getString("lastName"), - rs.getString("email"), - rs.getString("phone") - ); - - list.add(c); - } - - conn.close(); - return list; - } -} \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/database/EmployeeDB.java b/src/main/java/org/example/petshopdesktop/database/EmployeeDB.java deleted file mode 100644 index 18cd2167..00000000 --- a/src/main/java/org/example/petshopdesktop/database/EmployeeDB.java +++ /dev/null @@ -1,132 +0,0 @@ -package org.example.petshopdesktop.database; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -public class EmployeeDB { - - public static int ensureDefaultEmployee(String firstName, String lastName, String email, String phone, String role, boolean isActive) throws SQLException { - Integer existingId = findEmployeeIdByEmail(email); - if (existingId != null) { - return existingId; - } - - try (Connection conn = ConnectionDB.getConnection()) { - conn.setAutoCommit(false); - try { - int storeId = getDefaultStoreId(conn); - int employeeId = createEmployee(conn, firstName, lastName, email, phone, role, isActive); - assignEmployeeToStore(conn, employeeId, storeId); - conn.commit(); - return employeeId; - } catch (SQLException e) { - conn.rollback(); - throw e; - } finally { - conn.setAutoCommit(true); - } - } - } - - public static Integer findEmployeeIdByEmail(String email) throws SQLException { - String sql = "SELECT employeeId FROM employee WHERE email = ? LIMIT 1"; - try (Connection conn = ConnectionDB.getConnection(); - PreparedStatement ps = conn.prepareStatement(sql)) { - ps.setString(1, email); - try (ResultSet rs = ps.executeQuery()) { - if (rs.next()) { - return rs.getInt("employeeId"); - } - } - } - return null; - } - - public static int createEmployee(Connection conn, String firstName, String lastName, String email, String phone, String role, boolean isActive) throws SQLException { - String sql = "INSERT INTO employee (firstName, lastName, email, phone, role, isActive) VALUES (?, ?, ?, ?, ?, ?)"; - try (PreparedStatement ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { - ps.setString(1, firstName); - ps.setString(2, lastName); - ps.setString(3, email); - ps.setString(4, phone); - ps.setString(5, role); - ps.setBoolean(6, isActive); - ps.executeUpdate(); - - try (ResultSet keys = ps.getGeneratedKeys()) { - if (keys.next()) { - return keys.getInt(1); - } - } - } - - throw new SQLException("Could not create employee."); - } - - public static void assignEmployeeToStore(Connection conn, int employeeId, int storeId) throws SQLException { - String sql = "INSERT IGNORE INTO employeeStore (employeeId, storeId) VALUES (?, ?)"; - try (PreparedStatement ps = conn.prepareStatement(sql)) { - ps.setInt(1, employeeId); - ps.setInt(2, storeId); - ps.executeUpdate(); - } - } - - public static int getDefaultStoreId() throws SQLException { - try (Connection conn = ConnectionDB.getConnection()) { - return getDefaultStoreId(conn); - } - } - - public static int getDefaultStoreId(Connection conn) throws SQLException { - Integer existing = firstStoreId(conn); - if (existing != null) { - return existing; - } - - String insert = "INSERT INTO storeLocation (storeName, address, phone, email) VALUES ('Main Store', 'N/A', '000-000-0000', 'main@petshop.com')"; - try (PreparedStatement ps = conn.prepareStatement(insert, Statement.RETURN_GENERATED_KEYS)) { - ps.executeUpdate(); - try (ResultSet keys = ps.getGeneratedKeys()) { - if (keys.next()) { - return keys.getInt(1); - } - } - } - - Integer after = firstStoreId(conn); - if (after != null) { - return after; - } - - return 1; - } - - public static Integer getPrimaryStoreId(int employeeId) throws SQLException { - String sql = "SELECT storeId FROM employeeStore WHERE employeeId = ? ORDER BY storeId ASC LIMIT 1"; - try (Connection conn = ConnectionDB.getConnection(); - PreparedStatement ps = conn.prepareStatement(sql)) { - ps.setInt(1, employeeId); - try (ResultSet rs = ps.executeQuery()) { - if (rs.next()) { - return rs.getInt("storeId"); - } - } - } - return null; - } - - private static Integer firstStoreId(Connection conn) throws SQLException { - String sql = "SELECT storeId FROM storeLocation ORDER BY storeId ASC LIMIT 1"; - try (PreparedStatement ps = conn.prepareStatement(sql); - ResultSet rs = ps.executeQuery()) { - if (rs.next()) { - return rs.getInt("storeId"); - } - } - return null; - } -} diff --git a/src/main/java/org/example/petshopdesktop/database/InventoryDB.java b/src/main/java/org/example/petshopdesktop/database/InventoryDB.java deleted file mode 100644 index 792f9e6d..00000000 --- a/src/main/java/org/example/petshopdesktop/database/InventoryDB.java +++ /dev/null @@ -1,162 +0,0 @@ -package org.example.petshopdesktop.database; - -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import org.example.petshopdesktop.models.Inventory; -import org.example.petshopdesktop.util.ActivityLogger; - -import java.sql.*; - -public class InventoryDB { - - //Base selection query - //Returns invID, ProdID, Quantity from Inventory table - //Returns ProdName from Product table - private static final String BASE_SELECT = - "SELECT i.inventoryId, i.prodId, p.prodName, i.quantity " + - "FROM inventory i " + - "JOIN product p ON i.prodId = p.prodId"; - - - //Retrieves inventory records from DB - public static ObservableList getInventory() throws SQLException { - ObservableList inventoryList = FXCollections.observableArrayList(); - - Connection conn = ConnectionDB.getConnection(); - - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(BASE_SELECT); - - while (rs.next()) { - inventoryList.add(mapRow(rs)); - } - - conn.close(); - - return inventoryList; - } - - //Returns records depending on search - public static ObservableList getFilteredInventory(String filter) throws SQLException { - ObservableList inventoryList = FXCollections.observableArrayList(); - Connection conn = ConnectionDB.getConnection(); - - String sql = BASE_SELECT + - " WHERE i.inventoryId LIKE ? OR " + - "i.prodId LIKE ? OR " + - "p.prodName LIKE ? OR " + - "i.quantity LIKE ?"; - - String filteredString = "%" + filter + "%"; - PreparedStatement stmt = conn.prepareStatement(sql); - - for (int i = 1; i <= 4; i++) { - stmt.setString(i, filteredString); - } - - ResultSet rs = stmt.executeQuery(); - - while (rs.next()) { - inventoryList.add(mapRow(rs)); - } - - conn.close(); - - return inventoryList; - } - - //Checks if the product already has an inventory entry - public static boolean productExistsInInventory(int prodId) throws SQLException { - Connection conn = ConnectionDB.getConnection(); - String sql = "SELECT COUNT(*) FROM inventory WHERE prodId = ?"; - - PreparedStatement stmt = conn.prepareStatement(sql); - stmt.setInt(1, prodId); - ResultSet rs = stmt.executeQuery(); - - boolean exists = rs.next() && rs.getInt(1) > 0; - conn.close(); - - return exists; - } - - //Inserting new inventory record - public static int insertInventory(Inventory inventory) throws SQLException { - Connection conn = ConnectionDB.getConnection(); - String sql = "INSERT INTO inventory (prodId, quantity) VALUES (?, ?)"; - - PreparedStatement stmt = conn.prepareStatement(sql); - stmt.setInt(1, inventory.getProdId()); - stmt.setInt(2, inventory.getQuantity()); - - int numRows = stmt.executeUpdate(); - conn.close(); - - // Log the operation - if (numRows > 0) { - ActivityLogger.getInstance().logInsert("inventory", - "N/A", - String.format("Inventory added for Product ID %d, Quantity %d", inventory.getProdId(), inventory.getQuantity())); - } - - return numRows; - } - - //Updating inventory record - public static int updateInventory(int inventoryId, Inventory inventory) throws SQLException { - Connection conn = ConnectionDB.getConnection(); - String sql = "UPDATE inventory SET prodId = ?, quantity = ? WHERE inventoryId = ?"; - - PreparedStatement stmt = conn.prepareStatement(sql); - stmt.setInt(1, inventory.getProdId()); - stmt.setInt(2, inventory.getQuantity()); - stmt.setInt(3, inventoryId); - - int numRows = stmt.executeUpdate(); - conn.close(); - - // Log the operation - if (numRows > 0) { - ActivityLogger.getInstance().logUpdate("inventory", - String.valueOf(inventoryId), - String.format("Inventory ID %d updated", inventoryId)); - } - - return numRows; - } - - //Deleting inventory record - public static int deleteInventory(int inventoryId) throws SQLException { - Connection conn = ConnectionDB.getConnection(); - String sql = "DELETE FROM inventory WHERE inventoryId = ?"; - - PreparedStatement stmt = conn.prepareStatement(sql); - stmt.setInt(1, inventoryId); - - int numRows = stmt.executeUpdate(); - conn.close(); - - // Log the operation - if (numRows > 0) { - ActivityLogger.getInstance().logDelete("inventory", - String.valueOf(inventoryId), - String.format("Inventory ID %d deleted", inventoryId)); - } - - return numRows; - } - - //DRY: converts DB data into usable Java object - private static Inventory mapRow(ResultSet rs) throws SQLException { - return new Inventory( - rs.getInt("inventoryId"), - rs.getInt("prodId"), - rs.getString("prodName"), - "", - 0, - "", - rs.getInt("quantity"), - 0 - ); - } -} \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/database/PetDB.java b/src/main/java/org/example/petshopdesktop/database/PetDB.java deleted file mode 100644 index 5a748c4d..00000000 --- a/src/main/java/org/example/petshopdesktop/database/PetDB.java +++ /dev/null @@ -1,167 +0,0 @@ -package org.example.petshopdesktop.database; - -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import org.example.petshopdesktop.models.Pet; -import org.example.petshopdesktop.util.ActivityLogger; - -import java.sql.*; - -public class PetDB { - public static ObservableList getPets() throws SQLException { - //Connect to the database - ObservableList pets = FXCollections.observableArrayList(); - Connection conn = ConnectionDB.getConnection(); - - //Execute Query - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT * FROM pet"); - - //While there is still data add pets to the list - while(rs.next()){ - Pet pet = new Pet( - rs.getInt(1), - rs.getString(2), - rs.getString(3), - rs.getString(4), - rs.getInt(5), - rs.getString(6), - rs.getDouble(7) - ); - pets.add(pet); - } - - //close connection and return pets - conn.close(); - return pets; - } - - public static ObservableList getFilteredPets(String filter) throws SQLException { - //Connect to the database - ObservableList pets = FXCollections.observableArrayList(); - Connection conn = ConnectionDB.getConnection(); - - //Get SQL query for filtered word - String sql = "SELECT * FROM pet " + - " WHERE " + - "petName LIKE ? OR " + - "petSpecies LIKE ? OR " + - "petBreed LIKE ? OR " + - "petAge LIKE ? OR " + - "petStatus LIKE ? OR " + - "petPrice LIKE ?"; - - String filteredString = "%" + filter + "%"; - - PreparedStatement stmt = conn.prepareStatement(sql); - stmt.setString(1, filteredString); - stmt.setString(2, filteredString); - stmt.setString(3, filteredString); - stmt.setString(4, filteredString); - stmt.setString(5, filteredString); - stmt.setString(6, filteredString); - - ResultSet rs = stmt.executeQuery(); - - while(rs.next()){ - Pet pet = new Pet( - rs.getInt(1), - rs.getString(2), - rs.getString(3), - rs.getString(4), - rs.getInt(5), - rs.getString(6), - rs.getDouble(7) - ); - pets.add(pet); - } - - conn.close(); - return pets; - } - - public static int insertPet(Pet pet) throws SQLException { - int numRows = 0; - - Connection conn = ConnectionDB.getConnection(); - String sql = "INSERT INTO pet (petId, petName, petSpecies, petBreed, petAge, petStatus, petPrice)" + - " VALUES (?, ?, ?, ?, ?, ?, ?)"; - - PreparedStatement stmt = conn.prepareStatement(sql); - stmt.setInt(1, pet.getPetId()); - stmt.setString(2, pet.getPetName()); - stmt.setString(3, pet.getPetSpecies()); - stmt.setString(4, pet.getPetBreed()); - stmt.setInt(5, pet.getPetAge()); - stmt.setString(6, pet.getPetStatus()); - stmt.setDouble(7, pet.getPetPrice()); - - numRows = stmt.executeUpdate(); - conn.close(); - - // Log the operation - if (numRows > 0) { - ActivityLogger.getInstance().logInsert("pet", - String.valueOf(pet.getPetId()), - String.format("Pet '%s' added", pet.getPetName())); - } - - return numRows; - } - - public static int updatePet(int petId, Pet pet) throws SQLException { - int numRows = 0; - - Connection conn = ConnectionDB.getConnection(); - String sql = "UPDATE pet SET " + - " petName = ?, " + - " petSpecies = ?, " + - " petBreed = ?, " + - " petAge = ?, " + - " petStatus = ?, " + - " petPrice = ? " + - " WHERE petId = ?"; - PreparedStatement stmt = conn.prepareStatement(sql); - stmt.setString(1, pet.getPetName()); - stmt.setString(2, pet.getPetSpecies()); - stmt.setString(3, pet.getPetBreed()); - stmt.setInt(4, pet.getPetAge()); - stmt.setString(5, pet.getPetStatus()); - stmt.setDouble(6, pet.getPetPrice()); - stmt.setInt(7, petId); - - numRows = stmt.executeUpdate(); - conn.close(); - - // Log the operation - if (numRows > 0) { - ActivityLogger.getInstance().logUpdate("pet", - String.valueOf(petId), - String.format("Pet '%s' updated", pet.getPetName())); - } - - return numRows; - } - - public static int deletePet(int petId) throws SQLException { - int numRows = 0; - Connection conn = ConnectionDB.getConnection(); - - String sql = "DELETE FROM pet WHERE petId = ?"; - PreparedStatement stmt = conn.prepareStatement(sql); - - stmt.setInt(1, petId); - - numRows = stmt.executeUpdate(); - conn.close(); - - // Log the operation - if (numRows > 0) { - ActivityLogger.getInstance().logDelete("pet", - String.valueOf(petId), - String.format("Pet ID %d deleted", petId)); - } - - return numRows; - } -} diff --git a/src/main/java/org/example/petshopdesktop/database/ProductDB.java b/src/main/java/org/example/petshopdesktop/database/ProductDB.java deleted file mode 100644 index d8aa4da1..00000000 --- a/src/main/java/org/example/petshopdesktop/database/ProductDB.java +++ /dev/null @@ -1,234 +0,0 @@ -package org.example.petshopdesktop.database; - -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import org.example.petshopdesktop.DTOs.ProductDTO; -import org.example.petshopdesktop.models.Product; -import org.example.petshopdesktop.models.Supplier; -import org.example.petshopdesktop.util.ActivityLogger; - -import java.sql.*; - -/** - * A class containing all the methods relating to CRUD on Products table - */ -public class ProductDB { - - /** - * gets all the products into an observable list - * @return a list of all the products - * @throws SQLException if failed to find products in the database - */ - public static ObservableList getProducts() throws SQLException{ - //Connect to the database - ObservableList products = FXCollections.observableArrayList(); - Connection conn = ConnectionDB.getConnection(); - - //Execute Query - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT * FROM product"); - - //While there is still data add products to the list - while(rs.next()){ - Product product = new Product( - rs.getInt(1), - rs.getString(2), - rs.getDouble(3), - rs.getInt(4), - rs.getString(5)); - products.add(product); - } - - //close connection and return products - conn.close(); - return products; - } - - /** - * gets all the ProductDTOs into an observable list for display (displays categoryName instead of categoryId) - * @return the list of all the ProductDTOs - * @throws SQLException if failed to find products in the database - */ - public static ObservableList getProductDTO() throws SQLException{ - //Connect to the database - ObservableList products = FXCollections.observableArrayList(); - Connection conn = ConnectionDB.getConnection(); - - //Execute Query - Statement stmt = conn.createStatement(); - String sql = "SELECT p.prodId, p.prodName, p.prodPrice, p.categoryId, c.categoryName, p.prodDesc " + - "FROM product p " + - "LEFT JOIN category c ON p.categoryId = c.categoryId"; - ResultSet rs = stmt.executeQuery(sql); - - //While there is still data add products to the list - while(rs.next()){ - ProductDTO product = new ProductDTO( - rs.getInt(1), - rs.getString(2), - rs.getDouble(3), - rs.getInt(4), - rs.getString(5), - rs.getString(6)); - products.add(product); - } - - //close connection and return products - conn.close(); - return products; - } - - /** - * Inserts a new product to the database - * @param product product entity to be inserted - * @return number of rows affected in the database - * @throws SQLException if insertion failed - */ - public static int insertProduct(Product product) throws SQLException { - int numRows = 0; - - Connection conn = ConnectionDB.getConnection(); - String sql = "INSERT INTO product (prodId, prodName, prodPrice, categoryId, prodDesc)" + - "VALUES (?, ?, ?, ?, ?)"; - - //These are the values from product to put into the query above - PreparedStatement stmt = conn.prepareStatement(sql); - stmt.setInt(1, product.getProdId()); - stmt.setString(2, product.getProdName()); - stmt.setDouble(3, product.getProdPrice()); - stmt.setInt(4, product.getCategoryId()); - stmt.setString(5, product.getProdDesc()); - - //update the number of rows affected, return and close connection - numRows = stmt.executeUpdate(); - conn.close(); - - // Log the operation - if (numRows > 0) { - ActivityLogger.getInstance().logInsert("product", - String.valueOf(product.getProdId()), - String.format("Product '%s' added", product.getProdName())); - } - - return numRows; - } - - /** - * Update an existing product to the database - * @param prodId id of product - * @param product new product data - * @return number of rows affected in the database - * @throws SQLException if update failed - */ - public static int updateProduct(int prodId, Product product) throws SQLException { - int numRows = 0; - - Connection conn = ConnectionDB.getConnection(); - String sql = "UPDATE product SET " + - " prodName = ?, " + - " prodPrice = ?, " + - " categoryId = ?, " + - " prodDesc = ? " + - " WHERE prodId = ?"; - - //update values to query - PreparedStatement stmt = conn.prepareStatement(sql); - stmt.setString(1, product.getProdName()); - stmt.setDouble(2, product.getProdPrice()); - stmt.setInt(3, product.getCategoryId()); - stmt.setString(4, product.getProdDesc()); - stmt.setInt(5, prodId); - - //Update rows and close connection - numRows = stmt.executeUpdate(); - conn.close(); - - // Log the operation - if (numRows > 0) { - ActivityLogger.getInstance().logUpdate("product", - String.valueOf(prodId), - String.format("Product '%s' updated", product.getProdName())); - } - - return numRows; - } - - /** - * Delete a product from the database - * @param prodId product id to be deleted - * @return number of rows affected in the database - * @throws SQLException if delete failed - */ - public static int deleteProduct(int prodId) throws SQLException { - int numRows = 0; - Connection conn = ConnectionDB.getConnection(); - - String sql = "DELETE FROM product WHERE prodId = ?"; - PreparedStatement stmt = conn.prepareStatement(sql); - - stmt.setInt(1, prodId); - - //close connection and update rows affected - numRows = stmt.executeUpdate(); - conn.close(); - - // Log the operation - if (numRows > 0) { - ActivityLogger.getInstance().logDelete("product", - String.valueOf(prodId), - String.format("Product ID %d deleted", prodId)); - } - - return numRows; - } - - /** - * Gets a list of productDTOs that is filtered by a given string - * @param filter the word to filter table - * @return ObservableList of ProductDTOs with the filtered data - * @throws SQLException if getting products failed - */ - public static ObservableList getFilteredProductDTOs(String filter) throws SQLException { - //Connect to the database - ObservableList products = FXCollections.observableArrayList(); - Connection conn = ConnectionDB.getConnection(); - - //Get SQL query for filtered word - String sql = - "SELECT p.prodId, p.prodName, p.prodPrice, p.categoryId, c.categoryName, p.prodDesc" + - " FROM product p" + - " LEFT JOIN category c ON p.categoryId = c.categoryId" + - " WHERE " + - "prodName LIKE ? OR " + - "prodPrice LIKE ? OR " + - "categoryName LIKE ? OR " + - "prodDesc LIKE ?"; - - //add % wildcard so the query can use LIKE to filter data - String filteredString = "%" + filter + "%"; - - PreparedStatement stmt = conn.prepareStatement(sql); - stmt.setString(1, filteredString); - stmt.setString(2, filteredString); - stmt.setString(3, filteredString); - stmt.setString(4, filteredString); - - //execute query - ResultSet rs = stmt.executeQuery(); - - //While there is still data add products to the list - while(rs.next()){ - ProductDTO product = new ProductDTO( - rs.getInt(1), - rs.getString(2), - rs.getDouble(3), - rs.getInt(4), - rs.getString(5), - rs.getString(6)); - products.add(product); - } - - conn.close(); - return products; - } -} diff --git a/src/main/java/org/example/petshopdesktop/database/ProductSupplierDB.java b/src/main/java/org/example/petshopdesktop/database/ProductSupplierDB.java deleted file mode 100644 index 146cbc6c..00000000 --- a/src/main/java/org/example/petshopdesktop/database/ProductSupplierDB.java +++ /dev/null @@ -1,219 +0,0 @@ -package org.example.petshopdesktop.database; - -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import org.example.petshopdesktop.DTOs.ProductDTO; -import org.example.petshopdesktop.DTOs.ProductSupplierDTO; -import org.example.petshopdesktop.models.Product; -import org.example.petshopdesktop.models.ProductSupplier; -import org.example.petshopdesktop.util.ActivityLogger; - -import java.sql.*; - -public class ProductSupplierDB { - /** - * gets all the productSupplier into an observable list - * @return a list of all the productSupplierDTOs - * @throws SQLException if failed to find productSupplier in the database - */ - public static ObservableList getProductSupplierDTO() throws SQLException{ - //Connect to the database - ObservableList productSuppliers = FXCollections.observableArrayList(); - Connection conn = ConnectionDB.getConnection(); - - //Execute Query - Statement stmt = conn.createStatement(); - String sql = "SELECT ps.supId, ps.prodId, s.supCompany, p.prodName, ps.cost " + - "FROM productSupplier ps " + - "LEFT JOIN product p " + - "ON p.prodId = ps.prodId " + - "LEFT JOIN supplier s " + - "ON s.supId = ps.supId"; - ResultSet rs = stmt.executeQuery(sql); - - //While there is still data add productSupplier to list - while(rs.next()){ - ProductSupplierDTO productSupplier = new ProductSupplierDTO( - rs.getInt(1), - rs.getInt(2), - rs.getString(3), - rs.getString(4), - rs.getDouble(5) - ); - productSuppliers.add(productSupplier); - } - - //close connection and return products - conn.close(); - return productSuppliers; - } - - /** - * Gets a list of ProductSupplierDTOs that is filtered by a given string - * @param filter the word to filter table - * @return ObservableList of ProductSupplierDTOs with the filtered data - * @throws SQLException if getting productSuppliers failed - */ - public static ObservableList getFilteredProductSupplierDTO (String filter) throws SQLException { - //connect to the database - ObservableList productSuppliers = FXCollections.observableArrayList(); - Connection conn = ConnectionDB.getConnection(); - - //Get SQL query for filter word - String sql = - "SELECT ps.supId, ps.prodId, s.supCompany, p.prodName, ps.cost " + - "FROM product p " + - "LEFT JOIN productSupplier ps " + - "ON p.prodId = ps.prodId " + - "LEFT JOIN supplier s " + - "ON s.supId = ps.supId " + - "WHERE " + - "prodName LIKE ? OR " + - "supCompany LIKE ? OR " + - "cost LIKE ?"; - - //add % wildcard so query can use LIKE to filter data - String filteredString = "%" + filter + "%"; - - PreparedStatement stmt = conn.prepareStatement(sql); - stmt.setString(1, filteredString); - stmt.setString(2, filteredString); - stmt.setString(3, filteredString); - - //execute query - ResultSet rs = stmt.executeQuery(); - - //While there is still data add productSupplier to the list - while(rs.next()){ - ProductSupplierDTO productSupplier = new ProductSupplierDTO( - rs.getInt(1), - rs.getInt(2), - rs.getString(3), - rs.getString(4), - rs.getDouble(5) - ); - productSuppliers.add(productSupplier); - } - - conn.close(); - return productSuppliers; - } - - /** - * Inserts a new productSupplier to the database - * @param productSupplier productSupplier entity to be inserted - * @return number of rows affected - * @throws SQLException if insert failed - */ - public static int insertProductSupplier(ProductSupplier productSupplier) throws SQLException{ - int numRows = 0; - - Connection conn = ConnectionDB.getConnection(); - String sql = "INSERT INTO productSupplier (prodId, supId, cost) " + - "VALUES (?, ?, ?)"; - - //These are the values from productSupplier to put into query above - PreparedStatement stmt = conn.prepareStatement(sql); - stmt.setInt(1, productSupplier.getProdId()); - stmt.setInt(2, productSupplier.getSupId()); - stmt.setDouble(3, productSupplier.getCost()); - - //update number of rows affected, return and close connection - numRows = stmt.executeUpdate(); - conn.close(); - - // Log the operation - if (numRows > 0) { - ActivityLogger.getInstance().logInsert("productSupplier", - String.format("ProdID:%d-SupID:%d", productSupplier.getProdId(), productSupplier.getSupId()), - String.format("Product-Supplier relation added for Product ID %d, Supplier ID %d", productSupplier.getProdId(), productSupplier.getSupId())); - } - - return numRows; - } - - /** - * Update a productSupplier by deleting old productSupplier and inserting new one - * @param oldProdId old product id (used to change primary compound key) - * @param oldSupId old supplier id (used to change primary compound key) - * @param productSupplier productSupplier entity with new info to update (including new primary compound key) - * @return number of rows affected in database - * @throws SQLException if update failed - */ - public static int updateProductSupplier(int oldSupId, int oldProdId, ProductSupplier productSupplier) throws SQLException{ - int numRows = 0; - Connection conn = ConnectionDB.getConnection(); - - //Make transaction so update can be rolled back if insert failed - conn.setAutoCommit(false); - - try{ - //Delete old data first - String sql = "DELETE FROM productSupplier WHERE supId = ? AND prodId = ?"; - PreparedStatement stmt = conn.prepareStatement(sql); - stmt.setInt(1, oldSupId); - stmt.setInt(2, oldProdId); - numRows = stmt.executeUpdate(); - - //Then change the data by inserting a new relation with given keys (only if delete worked) - if(numRows > 0){ - sql = "INSERT INTO productSupplier (prodId, supId, cost) " + - "VALUES (?, ?, ?)"; - stmt = conn.prepareStatement(sql); - stmt.setInt(1, productSupplier.getProdId()); - stmt.setInt(2, productSupplier.getSupId()); - stmt.setDouble(3, productSupplier.getCost()); - numRows = stmt.executeUpdate(); - } - //Commit changes if both delete and insert worked - conn.commit(); - - // Log the operation - if (numRows > 0) { - ActivityLogger.getInstance().logUpdate("productSupplier", - String.format("ProdID:%d-SupID:%d", productSupplier.getProdId(), productSupplier.getSupId()), - String.format("Product-Supplier relation updated from ProdID:%d-SupID:%d to ProdID:%d-SupID:%d", oldProdId, oldSupId, productSupplier.getProdId(), productSupplier.getSupId())); - } - } - catch(SQLException e){ - //Rollback CRUD failed - conn.rollback(); - throw e; - } - finally { - //Set auto commit back to true before closing connection - conn.setAutoCommit(true); - conn.close(); - } - return numRows; - } - - /** - * Delete a productSupplier from the database - * @param prodId id of the product - * @param supId id of the supplier - * @return number of rows affected in the database - * @throws SQLException if delete failed - */ - public static int deleteProductSupplier(int supId, int prodId) throws SQLException{ - int numRows = 0; - Connection conn = ConnectionDB.getConnection(); - - String sql = "DELETE FROM productSupplier WHERE supId = ? AND prodId = ?"; - PreparedStatement stmt = conn.prepareStatement(sql); - stmt.setInt(1, supId); - stmt.setInt(2, prodId); - - numRows = stmt.executeUpdate(); - conn.close(); - - // Log the operation - if (numRows > 0) { - ActivityLogger.getInstance().logDelete("productSupplier", - String.format("ProdID:%d-SupID:%d", prodId, supId), - String.format("Product-Supplier relation deleted for Product ID %d, Supplier ID %d", prodId, supId)); - } - - return numRows; - } -} diff --git a/src/main/java/org/example/petshopdesktop/database/PurchaseOrderDB.java b/src/main/java/org/example/petshopdesktop/database/PurchaseOrderDB.java deleted file mode 100644 index 2dea4de4..00000000 --- a/src/main/java/org/example/petshopdesktop/database/PurchaseOrderDB.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.example.petshopdesktop.database; - -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import org.example.petshopdesktop.DTOs.PurchaseOrderDTO; - -import java.sql.*; - -public class PurchaseOrderDB { - - public static ObservableList getPurchaseOrders() - throws SQLException { - - ObservableList list = - FXCollections.observableArrayList(); - - Connection conn = ConnectionDB.getConnection(); - - String sql = """ - SELECT po.purchaseOrderId, - s.supCompany, - po.orderDate, - po.status - FROM purchaseOrder po - JOIN supplier s ON po.supId = s.supId - ORDER BY po.purchaseOrderId - """; - - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(sql); - - while (rs.next()) { - - list.add(new PurchaseOrderDTO( - rs.getInt("purchaseOrderId"), - rs.getString("supCompany"), - rs.getString("orderDate"), - rs.getString("status") - )); - } - - conn.close(); - return list; - } -} \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/database/SaleDB.java b/src/main/java/org/example/petshopdesktop/database/SaleDB.java deleted file mode 100644 index 0fe0f30f..00000000 --- a/src/main/java/org/example/petshopdesktop/database/SaleDB.java +++ /dev/null @@ -1,572 +0,0 @@ -package org.example.petshopdesktop.database; - -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import org.example.petshopdesktop.DTOs.SaleDTO; -import org.example.petshopdesktop.models.SaleCartItem; -import org.example.petshopdesktop.models.SaleDetail; -import org.example.petshopdesktop.models.SaleLineItem; -import org.example.petshopdesktop.models.analytics.*; -import org.example.petshopdesktop.util.ActivityLogger; - -import java.sql.*; -import java.time.LocalDate; - -public class SaleDB { - - /** - * Get all sale items with details - * @return ObservableList of SaleDTOs - * @throws SQLException if database operation fails - */ - public static ObservableList getSales() throws SQLException { - ObservableList sales = FXCollections.observableArrayList(); - Connection conn = ConnectionDB.getConnection(); - - String sql = """ - SELECT - s.saleId, - DATE_FORMAT(s.saleDate, '%Y-%m-%d %H:%i') as saleDate, - CONCAT(e.firstName, ' ', e.lastName) as employeeName, - p.prodName, - si.quantity, - si.unitPrice, - (si.quantity * si.unitPrice) as lineTotal, - s.paymentMethod - FROM sale s - JOIN saleItem si ON s.saleId = si.saleId - JOIN product p ON si.prodId = p.prodId - JOIN employee e ON s.employeeId = e.employeeId - ORDER BY s.saleDate DESC, s.saleId, si.saleItemId - """; - - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(sql); - - while (rs.next()) { - sales.add(new SaleDTO( - rs.getInt("saleId"), - rs.getString("saleDate"), - rs.getString("employeeName"), - rs.getString("prodName"), - rs.getInt("quantity"), - rs.getDouble("unitPrice"), - rs.getDouble("lineTotal"), - rs.getString("paymentMethod") - )); - } - - conn.close(); - return sales; - } - - /** - * Get filtered sale items - * @param filter search term - * @return ObservableList of SaleDTOs matching the filter - * @throws SQLException if database operation fails - */ - public static ObservableList getFilteredSales(String filter) throws SQLException { - ObservableList sales = FXCollections.observableArrayList(); - Connection conn = ConnectionDB.getConnection(); - - String sql = """ - SELECT - s.saleId, - DATE_FORMAT(s.saleDate, '%Y-%m-%d %H:%i') as saleDate, - CONCAT(e.firstName, ' ', e.lastName) as employeeName, - p.prodName, - si.quantity, - si.unitPrice, - (si.quantity * si.unitPrice) as lineTotal, - s.paymentMethod - FROM sale s - JOIN saleItem si ON s.saleId = si.saleId - JOIN product p ON si.prodId = p.prodId - JOIN employee e ON s.employeeId = e.employeeId - WHERE s.saleId LIKE ? - OR p.prodName LIKE ? - OR CONCAT(e.firstName, ' ', e.lastName) LIKE ? - OR s.paymentMethod LIKE ? - ORDER BY s.saleDate DESC, s.saleId, si.saleItemId - """; - - PreparedStatement pstmt = conn.prepareStatement(sql); - String searchPattern = "%" + filter + "%"; - pstmt.setString(1, searchPattern); - pstmt.setString(2, searchPattern); - pstmt.setString(3, searchPattern); - pstmt.setString(4, searchPattern); - - ResultSet rs = pstmt.executeQuery(); - - while (rs.next()) { - sales.add(new SaleDTO( - rs.getInt("saleId"), - rs.getString("saleDate"), - rs.getString("employeeName"), - rs.getString("prodName"), - rs.getInt("quantity"), - rs.getDouble("unitPrice"), - rs.getDouble("lineTotal"), - rs.getString("paymentMethod") - )); - } - - conn.close(); - return sales; - } - - public static ObservableList getSaleLineItems() throws SQLException { - ObservableList saleItems = FXCollections.observableArrayList(); - Connection conn = ConnectionDB.getConnection(); - - String sql = """ - SELECT - s.saleId, - DATE_FORMAT(s.saleDate, '%Y-%m-%d %H:%i') as saleDate, - CONCAT(e.firstName, ' ', e.lastName) as employeeName, - p.prodName, - si.quantity, - si.unitPrice, - (si.quantity * si.unitPrice) as total, - s.paymentMethod, - s.isRefund - FROM sale s - JOIN saleItem si ON s.saleId = si.saleId - JOIN product p ON si.prodId = p.prodId - JOIN employee e ON s.employeeId = e.employeeId - ORDER BY s.saleDate DESC, s.saleId, si.saleItemId - """; - - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(sql); - - while (rs.next()) { - saleItems.add(new SaleLineItem( - rs.getInt("saleId"), - rs.getString("saleDate"), - rs.getString("employeeName"), - rs.getString("prodName"), - rs.getInt("quantity"), - rs.getDouble("unitPrice"), - rs.getDouble("total"), - rs.getString("paymentMethod"), - rs.getBoolean("isRefund") - )); - } - - conn.close(); - return saleItems; - } - - public static int createSale(int employeeId, String paymentMethod, ObservableList cartItems) throws SQLException { - if (cartItems.isEmpty()) { - throw new SQLException("Cannot create sale with empty cart"); - } - - Connection conn = ConnectionDB.getConnection(); - conn.setAutoCommit(false); - - try { - double totalAmount = cartItems.stream().mapToDouble(SaleCartItem::getTotal).sum(); - - String insertSale = """ - INSERT INTO sale (saleDate, totalAmount, paymentMethod, employeeId, storeId) - VALUES (NOW(), ?, ?, ?, 1) - """; - - PreparedStatement saleStmt = conn.prepareStatement(insertSale, Statement.RETURN_GENERATED_KEYS); - saleStmt.setDouble(1, totalAmount); - saleStmt.setString(2, paymentMethod); - saleStmt.setInt(3, employeeId); - saleStmt.executeUpdate(); - - ResultSet rs = saleStmt.getGeneratedKeys(); - if (!rs.next()) { - throw new SQLException("Failed to get generated sale ID"); - } - int saleId = rs.getInt(1); - - String insertItem = """ - INSERT INTO saleItem (saleId, prodId, quantity, unitPrice) - VALUES (?, ?, ?, ?) - """; - - String updateInventory = """ - UPDATE inventory - SET quantity = quantity - ? - WHERE prodId = ? - """; - - PreparedStatement itemStmt = conn.prepareStatement(insertItem); - PreparedStatement invStmt = conn.prepareStatement(updateInventory); - - for (SaleCartItem item : cartItems) { - itemStmt.setInt(1, saleId); - itemStmt.setInt(2, item.getProdId()); - itemStmt.setInt(3, item.getQuantity()); - itemStmt.setDouble(4, item.getUnitPrice()); - itemStmt.executeUpdate(); - - invStmt.setInt(1, item.getQuantity()); - invStmt.setInt(2, item.getProdId()); - int updated = invStmt.executeUpdate(); - - if (updated == 0) { - throw new SQLException("Failed to update inventory for product ID " + item.getProdId()); - } - } - - conn.commit(); - - ActivityLogger.getInstance().logInsert("sale", - String.format("Sale ID: %d", saleId), - String.format("Created sale with %d items, total: $%.2f", cartItems.size(), totalAmount)); - - return saleId; - - } catch (SQLException e) { - conn.rollback(); - ActivityLogger.getInstance().logException("SaleDB.createSale", e, "Creating sale"); - throw e; - } finally { - conn.setAutoCommit(true); - conn.close(); - } - } - - public static ObservableList getDailySalesRevenue() throws SQLException { - ObservableList dailySales = FXCollections.observableArrayList(); - Connection conn = ConnectionDB.getConnection(); - - String sql = """ - SELECT DATE(s.saleDate) as saleDate, SUM(s.totalAmount) as revenue - FROM sale s - GROUP BY DATE(s.saleDate) - ORDER BY saleDate ASC - """; - - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(sql); - - while (rs.next()) { - LocalDate date = rs.getDate("saleDate").toLocalDate(); - double revenue = rs.getDouble("revenue"); - dailySales.add(new DailySalesData(date, revenue)); - } - - conn.close(); - return dailySales; - } - - public static ObservableList getTopProductsByRevenue(int limit) throws SQLException { - ObservableList products = FXCollections.observableArrayList(); - Connection conn = ConnectionDB.getConnection(); - - String sql = """ - SELECT p.prodName, SUM(si.quantity * si.unitPrice) as totalRevenue - FROM saleItem si - JOIN product p ON si.prodId = p.prodId - GROUP BY p.prodId, p.prodName - ORDER BY totalRevenue DESC - LIMIT ? - """; - - PreparedStatement pstmt = conn.prepareStatement(sql); - pstmt.setInt(1, limit); - ResultSet rs = pstmt.executeQuery(); - - while (rs.next()) { - String productName = rs.getString("prodName"); - double totalRevenue = rs.getDouble("totalRevenue"); - products.add(new ProductSalesData(productName, 0, totalRevenue)); - } - - conn.close(); - return products; - } - - public static ObservableList getTopProductsByQuantity(int limit) throws SQLException { - ObservableList products = FXCollections.observableArrayList(); - Connection conn = ConnectionDB.getConnection(); - - String sql = """ - SELECT p.prodName, SUM(si.quantity) as totalQuantity, - SUM(si.quantity * si.unitPrice) as totalRevenue - FROM saleItem si - JOIN product p ON si.prodId = p.prodId - GROUP BY p.prodId, p.prodName - ORDER BY totalQuantity DESC - LIMIT ? - """; - - PreparedStatement pstmt = conn.prepareStatement(sql); - pstmt.setInt(1, limit); - ResultSet rs = pstmt.executeQuery(); - - while (rs.next()) { - String productName = rs.getString("prodName"); - int totalQuantity = rs.getInt("totalQuantity"); - double totalRevenue = rs.getDouble("totalRevenue"); - products.add(new ProductSalesData(productName, totalQuantity, totalRevenue)); - } - - conn.close(); - return products; - } - - public static ObservableList getPaymentMethodDistribution() throws SQLException { - ObservableList paymentMethods = FXCollections.observableArrayList(); - Connection conn = ConnectionDB.getConnection(); - - String sql = """ - SELECT s.paymentMethod, COUNT(*) as transactionCount, - SUM(s.totalAmount) as totalRevenue - FROM sale s - GROUP BY s.paymentMethod - ORDER BY totalRevenue DESC - """; - - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(sql); - - while (rs.next()) { - String paymentMethod = rs.getString("paymentMethod"); - int transactionCount = rs.getInt("transactionCount"); - double totalRevenue = rs.getDouble("totalRevenue"); - paymentMethods.add(new PaymentMethodData(paymentMethod, transactionCount, totalRevenue)); - } - - conn.close(); - return paymentMethods; - } - - public static ObservableList getEmployeeSalesPerformance() throws SQLException { - ObservableList employees = FXCollections.observableArrayList(); - Connection conn = ConnectionDB.getConnection(); - - String sql = """ - SELECT CONCAT(e.firstName, ' ', e.lastName) as employeeName, - COUNT(DISTINCT s.saleId) as transactionCount, - SUM(s.totalAmount) as totalRevenue, - COALESCE(SUM(si.quantity), 0) as totalItemsSold - FROM sale s - JOIN employee e ON s.employeeId = e.employeeId - LEFT JOIN saleItem si ON s.saleId = si.saleId - GROUP BY e.employeeId, e.firstName, e.lastName - ORDER BY totalRevenue DESC - """; - - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(sql); - - while (rs.next()) { - String employeeName = rs.getString("employeeName"); - int transactionCount = rs.getInt("transactionCount"); - double totalRevenue = rs.getDouble("totalRevenue"); - int totalItemsSold = rs.getInt("totalItemsSold"); - employees.add(new EmployeeSalesData(employeeName, transactionCount, totalRevenue, totalItemsSold)); - } - - conn.close(); - return employees; - } - - public static SalesSummary getSalesSummary() throws SQLException { - Connection conn = ConnectionDB.getConnection(); - - String sql = """ - SELECT COUNT(DISTINCT s.saleId) as totalTransactions, - COALESCE(SUM(s.totalAmount), 0) as totalRevenue, - COALESCE(AVG(s.totalAmount), 0) as avgTransactionValue, - COALESCE(SUM(si.quantity), 0) as totalItemsSold - FROM sale s - LEFT JOIN saleItem si ON s.saleId = si.saleId - """; - - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(sql); - - SalesSummary summary = null; - if (rs.next()) { - int totalTransactions = rs.getInt("totalTransactions"); - double totalRevenue = rs.getDouble("totalRevenue"); - double avgTransactionValue = rs.getDouble("avgTransactionValue"); - int totalItemsSold = rs.getInt("totalItemsSold"); - summary = new SalesSummary(totalTransactions, totalRevenue, avgTransactionValue, totalItemsSold); - } - - conn.close(); - return summary; - } - - public static SaleDetail getSaleById(int saleId) throws SQLException { - Connection conn = ConnectionDB.getConnection(); - - String saleSql = """ - SELECT s.saleId, s.saleDate, s.totalAmount, s.paymentMethod, - CONCAT(e.firstName, ' ', e.lastName) as employeeName, - s.isRefund - FROM sale s - JOIN employee e ON s.employeeId = e.employeeId - WHERE s.saleId = ? - """; - - PreparedStatement saleStmt = conn.prepareStatement(saleSql); - saleStmt.setInt(1, saleId); - ResultSet saleRs = saleStmt.executeQuery(); - - if (!saleRs.next()) { - conn.close(); - throw new SQLException("Sale not found with ID: " + saleId); - } - - boolean isRefund = saleRs.getBoolean("isRefund"); - if (isRefund) { - conn.close(); - throw new SQLException("Cannot refund a refund transaction"); - } - - SaleDetail detail = new SaleDetail( - saleRs.getInt("saleId"), - saleRs.getTimestamp("saleDate").toLocalDateTime(), - saleRs.getDouble("totalAmount"), - saleRs.getString("paymentMethod"), - saleRs.getString("employeeName"), - FXCollections.observableArrayList() - ); - - String itemsSql = """ - SELECT si.prodId, p.prodName, si.quantity, si.unitPrice, - (si.quantity * si.unitPrice) as total - FROM saleItem si - JOIN product p ON si.prodId = p.prodId - WHERE si.saleId = ? - """; - - PreparedStatement itemsStmt = conn.prepareStatement(itemsSql); - itemsStmt.setInt(1, saleId); - ResultSet itemsRs = itemsStmt.executeQuery(); - - while (itemsRs.next()) { - detail.getItems().add(new SaleDetail.SaleDetailItem( - itemsRs.getInt("prodId"), - itemsRs.getString("prodName"), - itemsRs.getInt("quantity"), - itemsRs.getDouble("unitPrice"), - itemsRs.getDouble("total") - )); - } - - conn.close(); - return detail; - } - - public static boolean isRefunded(int saleId) throws SQLException { - Connection conn = ConnectionDB.getConnection(); - - String sql = """ - SELECT COUNT(*) as refundCount - FROM sale - WHERE originalSaleId = ? AND isRefund = TRUE - """; - - PreparedStatement pstmt = conn.prepareStatement(sql); - pstmt.setInt(1, saleId); - ResultSet rs = pstmt.executeQuery(); - - boolean refunded = false; - if (rs.next()) { - refunded = rs.getInt("refundCount") > 0; - } - - conn.close(); - return refunded; - } - - public static int createRefund(int originalSaleId, int employeeId, String paymentMethod, ObservableList refundItems) throws SQLException { - if (refundItems.isEmpty()) { - throw new SQLException("Cannot create refund with empty items"); - } - - Connection conn = ConnectionDB.getConnection(); - - SaleDetail originalSale = getSaleById(originalSaleId); - conn = ConnectionDB.getConnection(); - - if (isRefunded(originalSaleId)) { - throw new SQLException("This sale has already been refunded"); - } - - conn.setAutoCommit(false); - - try { - double totalAmount = -refundItems.stream().mapToDouble(SaleCartItem::getTotal).sum(); - - String insertSale = """ - INSERT INTO sale (saleDate, totalAmount, paymentMethod, employeeId, storeId, isRefund, originalSaleId) - VALUES (NOW(), ?, ?, ?, 1, TRUE, ?) - """; - - PreparedStatement saleStmt = conn.prepareStatement(insertSale, Statement.RETURN_GENERATED_KEYS); - saleStmt.setDouble(1, totalAmount); - saleStmt.setString(2, paymentMethod); - saleStmt.setInt(3, employeeId); - saleStmt.setInt(4, originalSaleId); - saleStmt.executeUpdate(); - - ResultSet rs = saleStmt.getGeneratedKeys(); - if (!rs.next()) { - throw new SQLException("Failed to get generated refund ID"); - } - int refundId = rs.getInt(1); - - String insertItem = """ - INSERT INTO saleItem (saleId, prodId, quantity, unitPrice) - VALUES (?, ?, ?, ?) - """; - - String updateInventory = """ - UPDATE inventory - SET quantity = quantity + ? - WHERE prodId = ? - """; - - PreparedStatement itemStmt = conn.prepareStatement(insertItem); - PreparedStatement invStmt = conn.prepareStatement(updateInventory); - - for (SaleCartItem item : refundItems) { - itemStmt.setInt(1, refundId); - itemStmt.setInt(2, item.getProdId()); - itemStmt.setInt(3, -item.getQuantity()); - itemStmt.setDouble(4, item.getUnitPrice()); - itemStmt.executeUpdate(); - - invStmt.setInt(1, item.getQuantity()); - invStmt.setInt(2, item.getProdId()); - int updated = invStmt.executeUpdate(); - - if (updated == 0) { - throw new SQLException("Failed to update inventory for product ID " + item.getProdId()); - } - } - - conn.commit(); - - ActivityLogger.getInstance().logInsert("sale", - String.format("Refund ID: %d", refundId), - String.format("Created refund for sale ID %d with %d items, total: $%.2f", originalSaleId, refundItems.size(), Math.abs(totalAmount))); - - return refundId; - - } catch (SQLException e) { - conn.rollback(); - ActivityLogger.getInstance().logException("SaleDB.createRefund", e, "Creating refund"); - throw e; - } finally { - conn.setAutoCommit(true); - conn.close(); - } - } -} diff --git a/src/main/java/org/example/petshopdesktop/database/ServiceDB.java b/src/main/java/org/example/petshopdesktop/database/ServiceDB.java deleted file mode 100644 index efa629cc..00000000 --- a/src/main/java/org/example/petshopdesktop/database/ServiceDB.java +++ /dev/null @@ -1,129 +0,0 @@ -package org.example.petshopdesktop.database; - -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import org.example.petshopdesktop.models.Service; -import org.example.petshopdesktop.util.ActivityLogger; - -import java.sql.*; - -public class ServiceDB { - - // - // GET ALL SERVICES - // - public static ObservableList getServices() throws SQLException { - - ObservableList list = FXCollections.observableArrayList(); - Connection conn = ConnectionDB.getConnection(); - - String sql = "SELECT * FROM service"; - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(sql); - - while (rs.next()) { - - Service service = new Service( - rs.getInt("serviceId"), - rs.getString("serviceName"), - rs.getString("serviceDesc"), - rs.getInt("serviceDuration"), - rs.getDouble("servicePrice") - ); - - list.add(service); - } - - conn.close(); - return list; - } - - // - // INSERT SERVICE - // - public static int insertService(Service service) throws SQLException { - - Connection conn = ConnectionDB.getConnection(); - - String sql = - "INSERT INTO service (serviceName, serviceDesc, serviceDuration, servicePrice) " + - "VALUES (?, ?, ?, ?)"; - - PreparedStatement stmt = conn.prepareStatement(sql); - - stmt.setString(1, service.getServiceName()); - stmt.setString(2, service.getServiceDesc()); - stmt.setInt(3, service.getServiceDuration()); - stmt.setDouble(4, service.getServicePrice()); - - int rows = stmt.executeUpdate(); - conn.close(); - - // Log the operation - if (rows > 0) { - ActivityLogger.getInstance().logInsert("service", - "N/A", - String.format("Service '%s' added", service.getServiceName())); - } - - return rows; - } - - // - // UPDATE SERVICE - // - public static int updateService(int id, Service service) throws SQLException { - - Connection conn = ConnectionDB.getConnection(); - - String sql = - "UPDATE service SET " + - "serviceName=?, serviceDesc=?, serviceDuration=?, servicePrice=? " + - "WHERE serviceId=?"; - - PreparedStatement stmt = conn.prepareStatement(sql); - - stmt.setString(1, service.getServiceName()); - stmt.setString(2, service.getServiceDesc()); - stmt.setInt(3, service.getServiceDuration()); - stmt.setDouble(4, service.getServicePrice()); - stmt.setInt(5, id); - - int rows = stmt.executeUpdate(); - conn.close(); - - // Log the operation - if (rows > 0) { - ActivityLogger.getInstance().logUpdate("service", - String.valueOf(id), - String.format("Service '%s' updated", service.getServiceName())); - } - - return rows; - } - - // - // DELETE SERVICE - // - public static int deleteService(int id) throws SQLException { - - Connection conn = ConnectionDB.getConnection(); - - String sql = "DELETE FROM service WHERE serviceId=?"; - - PreparedStatement stmt = conn.prepareStatement(sql); - stmt.setInt(1, id); - - int rows = stmt.executeUpdate(); - conn.close(); - - // Log the operation - if (rows > 0) { - ActivityLogger.getInstance().logDelete("service", - String.valueOf(id), - String.format("Service ID %d deleted", id)); - } - - return rows; - } -} \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/database/SupplierDB.java b/src/main/java/org/example/petshopdesktop/database/SupplierDB.java deleted file mode 100644 index 2d03cde4..00000000 --- a/src/main/java/org/example/petshopdesktop/database/SupplierDB.java +++ /dev/null @@ -1,202 +0,0 @@ -package org.example.petshopdesktop.database; - -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import org.example.petshopdesktop.models.Product; -import org.example.petshopdesktop.models.Supplier; -import org.example.petshopdesktop.util.ActivityLogger; - -import java.sql.*; - -/** - * A class containing all the methods relating to CRUD on Suppliers table - */ -public class SupplierDB { - - /** - * gets all the suppliers into an observable list - * @return a list of all the suppliers - * @throws SQLException if failed to find suppliers in the database - */ - public static ObservableList getSuppliers() throws SQLException { - //Connect to the database - ObservableList suppliers = FXCollections.observableArrayList(); - Connection conn = ConnectionDB.getConnection(); - - //Execute Query - Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT * FROM supplier"); - - //While there is still data add suppliers to the list - while(rs.next()){ - Supplier supplier = new Supplier( - rs.getInt(1), - rs.getString(2), - rs.getString(3), - rs.getString(4), - rs.getString(5), - rs.getString(6)); - suppliers.add(supplier); - } - - conn.close(); - return suppliers; - } - - /** - * Inserts a new supplier to the database - * @param supplier supplier entity to be inserted - * @return number of rows affected in the database - * @throws SQLException if insertion failed - */ - public static int insertSupplier(Supplier supplier) throws SQLException { - int numRows = 0; - - Connection conn = ConnectionDB.getConnection(); - String sql = "INSERT INTO supplier (supId, supCompany, supContactFirstName, supContactLastName, supEmail, supPhone)" + - "VALUES (?, ?, ?, ?, ?, ?)"; - - //These are the values from supplier to put into the query above - PreparedStatement stmt = conn.prepareStatement(sql); - stmt.setInt(1, supplier.getSupId()); - stmt.setString(2, supplier.getSupCompany()); - stmt.setString(3, supplier.getSupContactFirstName()); - stmt.setString(4, supplier.getSupContactLastName()); - stmt.setString(5, supplier.getSupEmail()); - stmt.setString(6, supplier.getSupPhone()); - - //update the number of rows affected, return and close connection - numRows = stmt.executeUpdate(); - conn.close(); - - // Log the operation - if (numRows > 0) { - ActivityLogger.getInstance().logInsert("supplier", - String.valueOf(supplier.getSupId()), - String.format("Supplier '%s' added", supplier.getSupCompany())); - } - - return numRows; - } - - /** - * Update an existing supplier to the database - * @param supId id of supplier - * @param supplier new supplier data - * @return number of rows affected in the database - * @throws SQLException if update failed - */ - public static int updateSupplier(int supId, Supplier supplier) throws SQLException { - int numRows = 0; - - Connection conn = ConnectionDB.getConnection(); - String sql = "UPDATE supplier SET " + - " supCompany = ?, " + - " supContactFirstName = ?, " + - " supContactLastName = ?, " + - " supEmail = ?, " + - " supPhone = ? " + - " WHERE supId = ?"; - - //updated values to update the supplier with the query above - PreparedStatement stmt = conn.prepareStatement(sql); - stmt.setString(1, supplier.getSupCompany()); - stmt.setString(2, supplier.getSupContactFirstName()); - stmt.setString(3, supplier.getSupContactLastName()); - stmt.setString(4, supplier.getSupEmail()); - stmt.setString(5, supplier.getSupPhone()); - stmt.setInt(6, supId); - - //Update the rows and close connection - numRows = stmt.executeUpdate(); - conn.close(); - - // Log the operation - if (numRows > 0) { - ActivityLogger.getInstance().logUpdate("supplier", - String.valueOf(supId), - String.format("Supplier '%s' updated", supplier.getSupCompany())); - } - - return numRows; - } - - /** - * Delete a supplier form the database - * @param supId supplier id to be deleted - * @return number of rows affected in the database - * @throws SQLException if delete failed - */ - public static int deleteSupplier(int supId) throws SQLException { - int numRows = 0; - Connection conn = ConnectionDB.getConnection(); - - String sql = "DELETE FROM supplier WHERE supId = ?"; - PreparedStatement stmt = conn.prepareStatement(sql); - //The supplier id to be deleted for the query above - stmt.setInt(1, supId); - - //close connection and update rows affected - numRows = stmt.executeUpdate(); - conn.close(); - - // Log the operation - if (numRows > 0) { - ActivityLogger.getInstance().logDelete("supplier", - String.valueOf(supId), - String.format("Supplier ID %d deleted", supId)); - } - - return numRows; - } - - /** - * Gets a list of Suppliers that is filtered by a given string - * @param filter the word to filter table - * @return ObservableList of suppliers with the filtered data - * @throws SQLException if getting suppliers failed - */ - public static ObservableList getFilteredSuppliers(String filter) throws SQLException { - //Connect to the database - ObservableList suppliers = FXCollections.observableArrayList(); - Connection conn = ConnectionDB.getConnection(); - - //Get SQL query for filtered word - String sql = - "SELECT * FROM supplier" + - " WHERE " + - "supCompany LIKE ? OR " + - "supContactFirstName LIKE ? OR " + - "supContactLastName LIKE ? OR " + - "supEmail LIKE ? OR " + - "supPhone LIKE ?"; - - //add % wildcard so the query can use LIKE to filter data - String filteredString = "%" + filter + "%"; - - PreparedStatement stmt = conn.prepareStatement(sql); - stmt.setString(1, filteredString); - stmt.setString(2, filteredString); - stmt.setString(3, filteredString); - stmt.setString(4, filteredString); - stmt.setString(5, filteredString); - - //execute query - ResultSet rs = stmt.executeQuery(); - - //While there is still data add suppliers to the list - while(rs.next()){ - Supplier supplier = new Supplier( - rs.getInt(1), - rs.getString(2), - rs.getString(3), - rs.getString(4), - rs.getString(5), - rs.getString(6)); - suppliers.add(supplier); - } - - conn.close(); - return suppliers; - } -} diff --git a/src/main/java/org/example/petshopdesktop/database/UserDB.java b/src/main/java/org/example/petshopdesktop/database/UserDB.java deleted file mode 100644 index ca4d8a78..00000000 --- a/src/main/java/org/example/petshopdesktop/database/UserDB.java +++ /dev/null @@ -1,198 +0,0 @@ -package org.example.petshopdesktop.database; - -import org.example.petshopdesktop.auth.Role; -import org.example.petshopdesktop.models.StaffAccount; -import org.example.petshopdesktop.models.User; -import org.example.petshopdesktop.util.ActivityLogger; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.List; - -public class UserDB { - - public static User authenticate(String username, String password) throws SQLException { - String sql = "SELECT u.user_id, u.employee_id, u.username, u.role, e.firstName, e.lastName " - + "FROM users u " - + "JOIN employee e ON u.employee_id = e.employeeId " - + "WHERE u.username = ? AND u.password_hash = SHA2(?, 256) AND e.isActive = TRUE"; - - try (Connection conn = ConnectionDB.getConnection(); - PreparedStatement ps = conn.prepareStatement(sql)) { - - ps.setString(1, username); - ps.setString(2, password); - - try (ResultSet rs = ps.executeQuery()) { - if (rs.next()) { - int userId = rs.getInt("user_id"); - int employeeId = rs.getInt("employee_id"); - String uname = rs.getString("username"); - Role role = Role.valueOf(rs.getString("role").toUpperCase()); - String firstName = rs.getString("firstName"); - String lastName = rs.getString("lastName"); - - return new User(userId, employeeId, uname, firstName, lastName, role); - } - } - } - - return null; - } - - public static void initializeTable() throws SQLException { - String createTable = """ - CREATE TABLE IF NOT EXISTS users ( - user_id INT AUTO_INCREMENT PRIMARY KEY, - employee_id INT NOT NULL, - username VARCHAR(100) NOT NULL UNIQUE, - password_hash CHAR(64) NOT NULL, - role ENUM('ADMIN','STAFF') NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, - FOREIGN KEY (employee_id) REFERENCES employee(employeeId) - ) - """; - - try (Connection conn = ConnectionDB.getConnection(); - Statement st = conn.createStatement()) { - st.executeUpdate(createTable); - } - - ensureCompatibleSchema(); - - int adminEmployeeId = EmployeeDB.ensureDefaultEmployee("John", "Doe", "john@petshop.com", "111-222-3333", "Manager", true); - int staffEmployeeId = EmployeeDB.ensureDefaultEmployee("Sara", "Smith", "sara@petshop.com", "444-555-6666", "Staff", true); - - ensureDefaultUser(adminEmployeeId, "admin", "admin123", Role.ADMIN); - ensureDefaultUser(staffEmployeeId, "staff", "staff123", Role.STAFF); - } - - public static int createStaffAccount(String firstName, String lastName, String email, String phone, String username, String password) throws SQLException { - if (username == null || username.isBlank()) { - throw new SQLException("Username is required."); - } - if (password == null || password.isBlank()) { - throw new SQLException("Password is required."); - } - - int storeId = EmployeeDB.getDefaultStoreId(); - - try (Connection conn = ConnectionDB.getConnection()) { - conn.setAutoCommit(false); - try { - int employeeId = EmployeeDB.createEmployee(conn, firstName, lastName, email, phone, "Staff", true); - EmployeeDB.assignEmployeeToStore(conn, employeeId, storeId); - - String insertUser = "INSERT INTO users (employee_id, username, password_hash, role) VALUES (?, ?, SHA2(?, 256), 'STAFF')"; - try (PreparedStatement ps = conn.prepareStatement(insertUser, Statement.RETURN_GENERATED_KEYS)) { - ps.setInt(1, employeeId); - ps.setString(2, username); - ps.setString(3, password); - ps.executeUpdate(); - - try (ResultSet keys = ps.getGeneratedKeys()) { - if (keys.next()) { - int userId = keys.getInt(1); - conn.commit(); - ActivityLogger.getInstance().logInsert("users", String.valueOf(userId), "Created staff account: " + username); - return userId; - } - } - } - - conn.rollback(); - throw new SQLException("Could not create staff account."); - } catch (SQLException e) { - conn.rollback(); - throw e; - } catch (RuntimeException e) { - conn.rollback(); - throw e; - } finally { - conn.setAutoCommit(true); - } - } - } - - public static List getStaffAccounts() throws SQLException { - String sql = "SELECT u.user_id, u.username, u.created_at, e.employeeId, e.firstName, e.lastName, e.email, e.phone, e.isActive " - + "FROM users u " - + "JOIN employee e ON u.employee_id = e.employeeId " - + "WHERE u.role = 'STAFF' " - + "ORDER BY u.created_at DESC"; - - List accounts = new ArrayList<>(); - - try (Connection conn = ConnectionDB.getConnection(); - PreparedStatement ps = conn.prepareStatement(sql); - ResultSet rs = ps.executeQuery()) { - - while (rs.next()) { - accounts.add(new StaffAccount( - rs.getInt("user_id"), - rs.getInt("employeeId"), - rs.getString("username"), - rs.getString("firstName"), - rs.getString("lastName"), - rs.getString("email"), - rs.getString("phone"), - rs.getBoolean("isActive"), - rs.getTimestamp("created_at") - )); - } - } - - return accounts; - } - - private static void ensureCompatibleSchema() throws SQLException { - try (Connection conn = ConnectionDB.getConnection(); - Statement st = conn.createStatement()) { - - try { - st.executeUpdate("ALTER TABLE users ADD COLUMN employee_id INT NULL"); - } catch (SQLException ignored) { - } - - try { - st.executeUpdate("ALTER TABLE users ADD COLUMN created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL"); - } catch (SQLException ignored) { - } - - try { - st.executeUpdate("ALTER TABLE users ADD CONSTRAINT fk_users_employee FOREIGN KEY (employee_id) REFERENCES employee(employeeId)"); - } catch (SQLException ignored) { - } - } - } - - private static void ensureDefaultUser(int employeeId, String username, String password, Role role) throws SQLException { - String insert = "INSERT IGNORE INTO users (employee_id, username, password_hash, role) VALUES (?, ?, SHA2(?, 256), ?)"; - String updateIfMissingEmployeeId = "UPDATE users SET employee_id = ? WHERE username = ? AND (employee_id IS NULL OR employee_id = 0)"; - - try (Connection conn = ConnectionDB.getConnection()) { - int rows; - try (PreparedStatement ps = conn.prepareStatement(insert)) { - ps.setInt(1, employeeId); - ps.setString(2, username); - ps.setString(3, password); - ps.setString(4, role.name()); - rows = ps.executeUpdate(); - } - - try (PreparedStatement ps = conn.prepareStatement(updateIfMissingEmployeeId)) { - ps.setInt(1, employeeId); - ps.setString(2, username); - ps.executeUpdate(); - } - - if (rows > 0) { - ActivityLogger.getInstance().logInsert("users", username, "Default " + role.name().toLowerCase() + " user created"); - } - } - } -} From 2bf09ea76da649a5678d56ffb0a43efabcb9c76b Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Sat, 7 Mar 2026 17:47:09 -0700 Subject: [PATCH 10/19] Remove docker configs and database run configuration --- Petstoredata.sql | 394 --------------------------------------------- docker-compose.yml | 18 --- 2 files changed, 412 deletions(-) delete mode 100644 Petstoredata.sql delete mode 100644 docker-compose.yml diff --git a/Petstoredata.sql b/Petstoredata.sql deleted file mode 100644 index 8c7c1576..00000000 --- a/Petstoredata.sql +++ /dev/null @@ -1,394 +0,0 @@ -DROP DATABASE IF EXISTS Petstoredb; -CREATE DATABASE Petstoredb; -USE Petstoredb; - --- Create Tables - -CREATE TABLE storeLocation ( - storeId INT AUTO_INCREMENT PRIMARY KEY, - storeName VARCHAR(100) NOT NULL, - address VARCHAR(255) NOT NULL, - phone VARCHAR(20) NOT NULL, - email VARCHAR(100) NOT NULL -); - -CREATE TABLE employee ( - employeeId INT AUTO_INCREMENT PRIMARY KEY, - firstName VARCHAR(50) NOT NULL, - lastName VARCHAR(50) NOT NULL, - email VARCHAR(100) NOT NULL, - phone VARCHAR(20) NOT NULL, - role VARCHAR(50) NOT NULL, - isActive BOOLEAN DEFAULT TRUE NOT NULL -); - -CREATE TABLE employeeStore ( - employeeId INT NOT NULL, - storeId INT NOT NULL, - PRIMARY KEY (employeeId, storeId), - FOREIGN KEY (employeeId) REFERENCES employee(employeeId), - FOREIGN KEY (storeId) REFERENCES storeLocation(storeId) -); - -CREATE TABLE customer ( - customerId INT AUTO_INCREMENT PRIMARY KEY, - firstName VARCHAR(50) NOT NULL, - lastName VARCHAR(50) NOT NULL, - email VARCHAR(100) NOT NULL, - phone VARCHAR(20) NOT NULL -); - -CREATE TABLE pet ( - petId INT AUTO_INCREMENT PRIMARY KEY, - petName VARCHAR(50) NOT NULL, - petSpecies VARCHAR(50) NOT NULL, - petBreed VARCHAR(50) NOT NULL, - petAge INT NOT NULL, - petStatus VARCHAR(20) NOT NULL, - petPrice DECIMAL(10, 2) NOT NULL -); - -CREATE TABLE adoption ( - adoptionId INT AUTO_INCREMENT PRIMARY KEY, - petId INT NOT NULL, - customerId INT NOT NULL, - adoptionDate DATE NOT NULL, - adoptionStatus VARCHAR(20) NOT NULL, - FOREIGN KEY (petId) REFERENCES pet(petId), - FOREIGN KEY (customerId) REFERENCES customer(customerId) -); - -CREATE TABLE supplier ( - supId INT AUTO_INCREMENT PRIMARY KEY, - supCompany VARCHAR(100) NOT NULL, - supContactFirstName VARCHAR(50) NOT NULL, - supContactLastName VARCHAR(50) NOT NULL, - supEmail VARCHAR(100) NOT NULL, - supPhone VARCHAR(20) NOT NULL -); - -CREATE TABLE category ( - categoryId INT AUTO_INCREMENT PRIMARY KEY, - categoryName VARCHAR(100) NOT NULL, - categoryType VARCHAR(50) NOT NULL -); - -CREATE TABLE product ( - prodId INT AUTO_INCREMENT PRIMARY KEY, - prodName VARCHAR(100) NOT NULL, - prodPrice DECIMAL(10, 2) NOT NULL, - categoryId INT NOT NULL, - prodDesc TEXT, - FOREIGN KEY (categoryId) REFERENCES category(categoryId) -); - -CREATE TABLE productSupplier ( - supId INT NOT NULL, - prodId INT NOT NULL, - cost DECIMAL(10, 2) NOT NULL, - PRIMARY KEY (supId, prodId), - FOREIGN KEY (supId) REFERENCES supplier(supId), - FOREIGN KEY (prodId) REFERENCES product(prodId) -); - -CREATE TABLE inventory ( - inventoryId INT AUTO_INCREMENT PRIMARY KEY, - prodId INT NOT NULL, - quantity INT DEFAULT 0 NOT NULL, - FOREIGN KEY (prodId) REFERENCES product(prodId) -); - -CREATE TABLE service ( - serviceId INT AUTO_INCREMENT PRIMARY KEY, - serviceName VARCHAR(100) NOT NULL, - serviceDesc TEXT, - serviceDuration INT NOT NULL, - servicePrice DECIMAL(10, 2) NOT NULL -); - -CREATE TABLE appointment ( - appointmentId INT AUTO_INCREMENT PRIMARY KEY, - serviceId INT NOT NULL, - customerId INT NOT NULL, - appointmentDate DATE NOT NULL, - appointmentTime TIME NOT NULL, - appointmentStatus VARCHAR(20) NOT NULL, - FOREIGN KEY (serviceId) REFERENCES service(serviceId), - FOREIGN KEY (customerId) REFERENCES customer(customerId) -); - -CREATE TABLE appointmentPet ( - appointmentId INT NOT NULL, - petId INT NOT NULL, - PRIMARY KEY (appointmentId, petId), - FOREIGN KEY (appointmentId) REFERENCES appointment(appointmentId), - FOREIGN KEY (petId) REFERENCES pet(petId) -); - -CREATE TABLE sale ( - saleId INT AUTO_INCREMENT PRIMARY KEY, - saleDate DATETIME NOT NULL, - totalAmount DECIMAL(10, 2) NOT NULL, - paymentMethod VARCHAR(50) NOT NULL, - employeeId INT NOT NULL, - storeId INT NOT NULL, - isRefund BOOLEAN DEFAULT FALSE NOT NULL, - originalSaleId INT NULL, - FOREIGN KEY (employeeId) REFERENCES employee(employeeId), - FOREIGN KEY (storeId) REFERENCES storeLocation(storeId), - FOREIGN KEY (originalSaleId) REFERENCES sale(saleId) -); - -CREATE TABLE saleItem ( - saleItemId INT AUTO_INCREMENT PRIMARY KEY, - saleId INT NOT NULL, - prodId INT NOT NULL, - quantity INT NOT NULL, - unitPrice DECIMAL(10, 2) NOT NULL, - FOREIGN KEY (saleId) REFERENCES sale(saleId), - FOREIGN KEY (prodId) REFERENCES product(prodId) -); - -CREATE TABLE purchaseOrder ( - purchaseOrderId INT AUTO_INCREMENT PRIMARY KEY, - supId INT NOT NULL, - orderDate DATE NOT NULL, - status VARCHAR(50) NOT NULL, - FOREIGN KEY (supId) REFERENCES supplier(supId) -); - -CREATE TABLE activityLog ( - logId INT AUTO_INCREMENT PRIMARY KEY, - employeeId INT NOT NULL, - activity TEXT NOT NULL, - logTimestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, - FOREIGN KEY (employeeId) REFERENCES employee(employeeId) -); - --- Insert Sample Data - -INSERT INTO storeLocation (storeName, address, phone, email) -VALUES -('Downtown Branch', '123 Main St', '123-456-7890', 'downtown@petshop.com'), -('North Branch', '456 North Ave', '987-654-3210', 'north@petshop.com'), -('West Side Store', '789 West Blvd', '555-123-4567', 'westside@petshop.com'), -('East End Shop', '321 East Road', '555-987-6543', 'eastend@petshop.com'), -('South Mall Location', '654 South Plaza', '555-246-8135', 'southmall@petshop.com'); - -INSERT INTO employee (firstName, lastName, email, phone, role, isActive) -VALUES -('John', 'Doe', 'john@petshop.com', '111-222-3333', 'Manager', TRUE), -('Sara', 'Smith', 'sara@petshop.com', '444-555-6666', 'Staff', TRUE), -('Michael', 'Johnson', 'michael@petshop.com', '222-333-4444', 'Groomer', TRUE), -('Lisa', 'Williams', 'lisa@petshop.com', '333-444-5555', 'Staff', TRUE), -('David', 'Brown', 'david@petshop.com', '555-666-7777', 'Veterinarian', TRUE), -('Emma', 'Davis', 'emma@petshop.com', '666-777-8888', 'Manager', FALSE); - -INSERT INTO employeeStore (employeeId, storeId) -VALUES -(1, 1), -(2, 1), -(2, 2), -(3, 2), -(4, 3), -(5, 1), -(5, 4), -(6, 5); - -INSERT INTO customer (firstName, lastName, email, phone) -VALUES -('Alex', 'Brown', 'alex@gmail.com', '777-888-9999'), -('Emily', 'Clark', 'emily@gmail.com', '666-555-4444'), -('James', 'Wilson', 'james@gmail.com', '888-999-0000'), -('Olivia', 'Martinez', 'olivia@gmail.com', '999-000-1111'), -('William', 'Anderson', 'william@gmail.com', '000-111-2222'), -('Sophia', 'Taylor', 'sophia@gmail.com', '111-222-3333'); - -INSERT INTO pet (petName, petSpecies, petBreed, petAge, petStatus, petPrice) -VALUES -('Buddy', 'Dog', 'Labrador', 2, 'Available', 500.00), -('Milo', 'Cat', 'Persian', 1, 'Available', 300.00), -('Charlie', 'Dog', 'Golden Retriever', 3, 'Available', 550.00), -('Luna', 'Cat', 'Siamese', 2, 'Adopted', 350.00), -('Max', 'Dog', 'Beagle', 1, 'Available', 450.00), -('Bella', 'Cat', 'Maine Coon', 4, 'Available', 400.00); - -INSERT INTO adoption (petId, customerId, adoptionDate, adoptionStatus) -VALUES -(1, 1, '2026-01-15', 'Completed'), -(4, 3, '2026-01-20', 'Completed'), -(2, 2, '2026-01-25', 'Pending'), -(5, 4, '2026-02-01', 'Completed'), -(6, 5, '2026-02-02', 'Pending'); - -INSERT INTO supplier (supCompany, supContactFirstName, supContactLastName, supEmail, supPhone) -VALUES -('PetFood Inc', 'Robert', 'King', 'contact@petfood.com', '888-111-2222'), -('Toy World', 'Jennifer', 'Lee', 'sales@toyworld.com', '888-222-3333'), -('Pet Supplies Co', 'Kevin', 'White', 'info@petsupplies.com', '888-333-4444'), -('Animal Care Products', 'Nancy', 'Green', 'orders@animalcare.com', '888-444-5555'), -('Premium Pet Goods', 'Tom', 'Black', 'support@premiumpet.com', '888-555-6666'); - -INSERT INTO category (categoryName, categoryType) -VALUES -('Dog Food', 'Product'), -('Cat Toys', 'Product'), -('Bird Supplies', 'Product'), -('Aquarium', 'Product'), -('Small Animals', 'Product'); - -INSERT INTO product (prodName, prodPrice, categoryId, prodDesc) -VALUES -('Premium Dog Food', 50.00, 1, 'High quality dog food'), -('Cat Toy Ball', 10.00, 2, 'Colorful toy for cats'), -('Bird Cage Large', 120.00, 3, 'Spacious bird cage'), -('Fish Tank 20 Gallon', 80.00, 4, 'Complete aquarium kit'), -('Hamster Wheel', 15.00, 5, 'Exercise wheel for small pets'), -('Organic Dog Treats', 25.00, 1, 'Natural dog treats'); - -INSERT INTO productSupplier (supId, prodId, cost) -VALUES -(1, 1, 35.00), -(1, 2, 6.50), -(2, 2, 7.00), -(3, 3, 90.00), -(3, 4, 60.00), -(4, 5, 10.00), -(5, 6, 18.00), -(1, 6, 17.50); - -INSERT INTO inventory (prodId, quantity) -VALUES -(1, 100), -(2, 200), -(3, 50), -(4, 30), -(5, 150), -(6, 75); - -INSERT INTO service (serviceName, serviceDesc, serviceDuration, servicePrice) -VALUES -('Pet Grooming', 'Full grooming service', 60, 40.00), -('Nail Trimming', 'Quick nail trim', 15, 10.00), -('Bath and Brush', 'Bathing and brushing service', 45, 30.00), -('Veterinary Checkup', 'Complete health examination', 30, 75.00), -('Teeth Cleaning', 'Professional dental cleaning', 90, 100.00); - -INSERT INTO appointment (serviceId, customerId, appointmentDate, appointmentTime, appointmentStatus) -VALUES -(1, 2, '2026-02-01', '10:30:00', 'Booked'), -(2, 1, '2026-02-03', '14:00:00', 'Booked'), -(3, 3, '2026-02-05', '09:00:00', 'Completed'), -(4, 4, '2026-02-07', '11:30:00', 'Booked'), -(5, 5, '2026-02-10', '15:00:00', 'Cancelled'); - -INSERT INTO appointmentPet (appointmentId, petId) -VALUES -(1, 2), -(2, 1), -(3, 3), -(4, 5), -(5, 6); - -INSERT INTO sale (saleDate, totalAmount, paymentMethod, employeeId, storeId) -VALUES --- January Sales -('2026-01-05 09:15:00', 125.00, 'Card', 1, 1), -- Sale 1: Dog food + treats -('2026-01-08 11:30:00', 200.00, 'Card', 2, 1), -- Sale 2: Bird cage + fish tank -('2026-01-12 14:20:00', 60.00, 'Cash', 3, 2), -- Sale 3: Cat toys + hamster wheel -('2026-01-15 10:45:00', 150.00, 'Debit', 1, 1), -- Sale 4: Dog food (bulk purchase) -('2026-01-18 16:30:00', 80.00, 'Card', 4, 3), -- Sale 5: Fish tank -('2026-01-22 13:15:00', 95.00, 'Cash', 2, 2), -- Sale 6: Mixed items -('2026-01-25 15:40:00', 240.00, 'Card', 5, 4), -- Sale 7: Two bird cages -('2026-01-28 10:30:00', 80.00, 'Cash', 1, 1), -- Sale 8: Dog food + cat toys --- February Sales -('2026-02-01 09:00:00', 175.00, 'Card', 3, 3), -- Sale 9: Dog food + treats (bulk) -('2026-02-03 11:20:00', 120.00, 'Card', 2, 1), -- Sale 10: Bird cage -('2026-02-05 14:50:00', 45.00, 'Cash', 4, 2), -- Sale 11: Hamster wheel + cat toys -('2026-02-08 16:15:00', 160.00, 'Debit', 1, 1), -- Sale 12: Fish tank + accessories -('2026-02-10 10:25:00', 100.00, 'Card', 5, 4), -- Sale 13: Dog treats (bulk) -('2026-02-12 13:45:00', 50.00, 'Cash', 2, 2), -- Sale 14: Dog food -('2026-02-15 15:30:00', 85.00, 'Card', 3, 3), -- Sale 15: Mixed pet supplies -('2026-02-18 11:10:00', 200.00, 'Card', 1, 1), -- Sale 16: Bird cage + hamster wheel -('2026-02-20 14:35:00', 155.00, 'Debit', 4, 3), -- Sale 17: Fish tank + cat toys -('2026-02-22 16:50:00', 75.00, 'Cash', 2, 1), -- Sale 18: Dog treats + toys -('2026-02-24 10:15:00', 140.00, 'Card', 5, 4), -- Sale 19: Dog food + treats -(NOW(), 95.00, 'Card', 1, 1); -- Sale 20: Recent sale (current timestamp) - -INSERT INTO saleItem (saleId, prodId, quantity, unitPrice) -VALUES --- Sale 1 items (Dog food + treats) -(1, 1, 2, 50.00), -- 2x Premium Dog Food -(1, 6, 1, 25.00), -- 1x Organic Dog Treats --- Sale 2 items (Bird cage + fish tank) -(2, 3, 1, 120.00), -- 1x Bird Cage Large -(2, 4, 1, 80.00), -- 1x Fish Tank 20 Gallon --- Sale 3 items (Cat toys + hamster wheel) -(3, 2, 3, 10.00), -- 3x Cat Toy Ball -(3, 5, 2, 15.00), -- 2x Hamster Wheel --- Sale 4 items (Dog food bulk) -(4, 1, 3, 50.00), -- 3x Premium Dog Food --- Sale 5 items (Fish tank) -(5, 4, 1, 80.00), -- 1x Fish Tank 20 Gallon --- Sale 6 items (Mixed) -(6, 2, 4, 10.00), -- 4x Cat Toy Ball -(6, 5, 1, 15.00), -- 1x Hamster Wheel -(6, 6, 1, 25.00), -- 1x Organic Dog Treats -(6, 1, 1, 50.00), -- 1x Premium Dog Food (partial - discount applied) --- Sale 7 items (Two bird cages) -(7, 3, 2, 120.00), -- 2x Bird Cage Large --- Sale 8 items (Dog food + cat toys) -(8, 1, 1, 50.00), -- 1x Premium Dog Food -(8, 2, 3, 10.00), -- 3x Cat Toy Ball --- Sale 9 items (Dog food + treats bulk) -(9, 1, 3, 50.00), -- 3x Premium Dog Food -(9, 6, 1, 25.00), -- 1x Organic Dog Treats --- Sale 10 items (Bird cage) -(10, 3, 1, 120.00), -- 1x Bird Cage Large --- Sale 11 items (Hamster wheel + cat toys) -(11, 5, 1, 15.00), -- 1x Hamster Wheel -(11, 2, 3, 10.00), -- 3x Cat Toy Ball --- Sale 12 items (Fish tank + accessories) -(12, 4, 2, 80.00), -- 2x Fish Tank 20 Gallon --- Sale 13 items (Dog treats bulk) -(13, 6, 4, 25.00), -- 4x Organic Dog Treats --- Sale 14 items (Dog food) -(14, 1, 1, 50.00), -- 1x Premium Dog Food --- Sale 15 items (Mixed supplies) -(15, 2, 2, 10.00), -- 2x Cat Toy Ball -(15, 5, 1, 15.00), -- 1x Hamster Wheel -(15, 6, 2, 25.00), -- 2x Organic Dog Treats --- Sale 16 items (Bird cage + hamster wheel) -(16, 3, 1, 120.00), -- 1x Bird Cage Large -(16, 4, 1, 80.00), -- 1x Fish Tank 20 Gallon --- Sale 17 items (Fish tank + cat toys) -(17, 4, 1, 80.00), -- 1x Fish Tank 20 Gallon -(17, 1, 1, 50.00), -- 1x Premium Dog Food -(17, 6, 1, 25.00), -- 1x Organic Dog Treats --- Sale 18 items (Dog treats + toys) -(18, 6, 2, 25.00), -- 2x Organic Dog Treats -(18, 2, 2, 10.00), -- 2x Cat Toy Ball -(18, 5, 1, 15.00), -- 1x Hamster Wheel --- Sale 19 items (Dog food + treats) -(19, 1, 2, 50.00), -- 2x Premium Dog Food -(19, 6, 2, 25.00), -- 2x Organic Dog Treats (discount applied) --- Sale 20 items (Recent sale) -(20, 2, 5, 10.00), -- 5x Cat Toy Ball -(20, 5, 3, 15.00); -- 3x Hamster Wheel - -INSERT INTO purchaseOrder (supId, orderDate, status) -VALUES -(1, '2025-01-15', 'Delivered'), -(2, '2025-01-20', 'Pending'), -(3, '2025-02-01', 'Delivered'), -(4, '2025-02-10', 'In Transit'), -(1, '2025-02-15', 'Pending'); - -INSERT INTO activityLog (employeeId, activity) -VALUES -(1, 'Created new sale'), -(2, 'Booked appointment'), -(3, 'Completed grooming service'), -(4, 'Processed inventory order'), -(5, 'Conducted health checkup'), -(1, 'Updated customer information'); \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 6703b07c..00000000 --- a/docker-compose.yml +++ /dev/null @@ -1,18 +0,0 @@ -services: - mysql: - image: mysql:8.4 - container_name: petstore-mysql - ports: - - "3306:3306" - environment: - MYSQL_ROOT_PASSWORD: rootpass - MYSQL_DATABASE: Petstoredb - MYSQL_USER: petapp - MYSQL_PASSWORD: petapppass - volumes: - - ./Petstoredata.sql:/docker-entrypoint-initdb.d/01-Petstoredata.sql:ro - - petstore_mysql_data:/var/lib/mysql - -volumes: - petstore_mysql_data: - From aa011205a0a0a4698c7a85add9f5b0380bccf533 Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Sat, 7 Mar 2026 17:53:41 -0700 Subject: [PATCH 11/19] Configure Jackson to ignore unknown properties --- log.txt | 4 ++++ src/main/java/org/example/petshopdesktop/api/ApiClient.java | 1 + 2 files changed, 5 insertions(+) diff --git a/log.txt b/log.txt index 273796fb..d142919d 100644 --- a/log.txt +++ b/log.txt @@ -45,3 +45,7 @@ The last packet sent successfully to the server was 0 milliseconds ago. The driv The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server. | Context: Establishing database connection [2026-03-02 13:02:48] [INSERT] DB_INSERT | Table: sale | ID: Refund ID: 24 | Details: Created refund for sale ID 23 with 1 items, total: $240.00 +[2026-03-07 17:50:34] [ERROR] EXCEPTION | Location: LoginController.btnLoginClicked | Type: MismatchedInputException | Message: Cannot deserialize value of type `java.lang.String` from Array value (token `JsonToken.START_ARRAY`) + at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 1] | Context: Authentication attempt for username: staff +[2026-03-07 17:50:34] [ERROR] EXCEPTION | Location: LoginController.btnLoginClicked | Type: MismatchedInputException | Message: Cannot deserialize value of type `java.lang.String` from Array value (token `JsonToken.START_ARRAY`) + at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 1] | Context: Authentication attempt for username: staff diff --git a/src/main/java/org/example/petshopdesktop/api/ApiClient.java b/src/main/java/org/example/petshopdesktop/api/ApiClient.java index e8f5a2b4..9563fae3 100644 --- a/src/main/java/org/example/petshopdesktop/api/ApiClient.java +++ b/src/main/java/org/example/petshopdesktop/api/ApiClient.java @@ -22,6 +22,7 @@ public class ApiClient { .build(); this.objectMapper = new ObjectMapper(); this.objectMapper.registerModule(new JavaTimeModule()); + this.objectMapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); this.baseUrl = ApiConfig.getInstance().getBaseUrl(); } From 59de8ae1aa6dd5f7da81ed97cd88b4d91977597e Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Sun, 8 Mar 2026 10:05:09 -0600 Subject: [PATCH 12/19] Fix null pointers and unsafe parsing bugs --- .../example/petshopdesktop/api/ApiClient.java | 23 +++++++++++ .../api/endpoints/AdoptionApi.java | 16 ++++++-- .../api/endpoints/AppointmentApi.java | 16 ++++++-- .../api/endpoints/DropdownApi.java | 35 +++++++++++++---- .../api/endpoints/InventoryApi.java | 16 ++++++-- .../petshopdesktop/api/endpoints/PetApi.java | 16 ++++++-- .../api/endpoints/ProductApi.java | 16 ++++++-- .../api/endpoints/ProductSupplierApi.java | 16 ++++++-- .../api/endpoints/PurchaseOrderApi.java | 16 ++++++-- .../petshopdesktop/api/endpoints/SaleApi.java | 16 ++++++-- .../api/endpoints/ServiceApi.java | 16 ++++++-- .../api/endpoints/SupplierApi.java | 16 ++++++-- .../petshopdesktop/api/endpoints/UserApi.java | 16 ++++++-- .../controllers/LoginController.java | 12 +++++- .../AdoptionDialogController.java | 27 ++++++++++--- .../AppointmentDialogController.java | 38 ++++++++++++++----- .../InventoryDialogController.java | 36 ++++++++++++------ .../PetDialogController.java | 19 ++++++++-- .../ProductDialogController.java | 22 ++++++++--- .../ProductSupplierDialogController.java | 14 +++++-- .../SupplierDialogController.java | 6 ++- 21 files changed, 328 insertions(+), 80 deletions(-) diff --git a/src/main/java/org/example/petshopdesktop/api/ApiClient.java b/src/main/java/org/example/petshopdesktop/api/ApiClient.java index 9563fae3..a2e0e279 100644 --- a/src/main/java/org/example/petshopdesktop/api/ApiClient.java +++ b/src/main/java/org/example/petshopdesktop/api/ApiClient.java @@ -44,6 +44,28 @@ public class ApiClient { return handleResponse(response, responseClass); } + public String getRawResponse(String path) throws Exception { + HttpRequest.Builder builder = HttpRequest.newBuilder() + .uri(URI.create(baseUrl + path)) + .GET() + .timeout(Duration.ofSeconds(30)); + + addAuthHeader(builder); + + HttpRequest request = builder.build(); + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + + if (response.statusCode() == 200 || response.statusCode() == 201) { + return response.body(); + } else if (response.statusCode() == 401) { + throw new RuntimeException("Authentication failed. Please log in again."); + } else if (response.statusCode() == 403) { + throw new RuntimeException("Access restricted. You don't have permission to perform this action."); + } else { + throw new RuntimeException(parseErrorMessage(response)); + } + } + public T post(String path, Object requestBody, Class responseClass) throws Exception { String jsonBody = objectMapper.writeValueAsString(requestBody); @@ -155,6 +177,7 @@ public class ApiClient { } } } catch (Exception e) { + System.err.println("Error parsing error message: " + e.getMessage()); } return "Request failed with status " + response.statusCode(); } diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/AdoptionApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/AdoptionApi.java index f5c0f8e4..d4f90c85 100644 --- a/src/main/java/org/example/petshopdesktop/api/endpoints/AdoptionApi.java +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/AdoptionApi.java @@ -5,7 +5,10 @@ import org.example.petshopdesktop.api.ApiClient; import org.example.petshopdesktop.api.dto.adoption.AdoptionRequest; import org.example.petshopdesktop.api.dto.adoption.AdoptionResponse; import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest; +import org.example.petshopdesktop.api.dto.common.PageResponse; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.List; public class AdoptionApi { @@ -23,10 +26,17 @@ public class AdoptionApi { public List listAdoptions(String query) throws Exception { String path = "/api/v1/adoptions?page=0&size=1000"; if (query != null && !query.isEmpty()) { - path += "&q=" + query; + path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8); } - String response = apiClient.get(path, String.class); - return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + String response = apiClient.getRawResponse(path); + PageResponse pageResponse = apiClient.getObjectMapper().readValue( + response, + new TypeReference>() {} + ); + if (pageResponse == null) { + throw new IllegalStateException("Null response from adoptions endpoint"); + } + return pageResponse.getContent(); } public AdoptionResponse createAdoption(AdoptionRequest request) throws Exception { diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/AppointmentApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/AppointmentApi.java index e7d1410a..4dd65bf0 100644 --- a/src/main/java/org/example/petshopdesktop/api/endpoints/AppointmentApi.java +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/AppointmentApi.java @@ -5,7 +5,10 @@ import org.example.petshopdesktop.api.ApiClient; import org.example.petshopdesktop.api.dto.appointment.AppointmentRequest; import org.example.petshopdesktop.api.dto.appointment.AppointmentResponse; import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest; +import org.example.petshopdesktop.api.dto.common.PageResponse; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.List; public class AppointmentApi { @@ -23,10 +26,17 @@ public class AppointmentApi { public List listAppointments(String query) throws Exception { String path = "/api/v1/appointments?page=0&size=1000"; if (query != null && !query.isEmpty()) { - path += "&q=" + query; + path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8); } - String response = apiClient.get(path, String.class); - return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + String response = apiClient.getRawResponse(path); + PageResponse pageResponse = apiClient.getObjectMapper().readValue( + response, + new TypeReference>() {} + ); + if (pageResponse == null) { + throw new IllegalStateException("Null response from appointments endpoint"); + } + return pageResponse.getContent(); } public AppointmentResponse createAppointment(AppointmentRequest request) throws Exception { diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/DropdownApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/DropdownApi.java index bff7998c..6c20526e 100644 --- a/src/main/java/org/example/petshopdesktop/api/endpoints/DropdownApi.java +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/DropdownApi.java @@ -19,37 +19,58 @@ public class DropdownApi { } public List getCategories() throws Exception { - String response = apiClient.get("/api/v1/dropdowns/categories", String.class); + String response = apiClient.getRawResponse("/api/v1/dropdowns/categories"); + if (response == null || response.isEmpty()) { + throw new IllegalStateException("Empty response from categories endpoint"); + } return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); } public List getProducts() throws Exception { - String response = apiClient.get("/api/v1/dropdowns/products", String.class); + String response = apiClient.getRawResponse("/api/v1/dropdowns/products"); + if (response == null || response.isEmpty()) { + throw new IllegalStateException("Empty response from products endpoint"); + } return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); } public List getSuppliers() throws Exception { - String response = apiClient.get("/api/v1/dropdowns/suppliers", String.class); + String response = apiClient.getRawResponse("/api/v1/dropdowns/suppliers"); + if (response == null || response.isEmpty()) { + throw new IllegalStateException("Empty response from suppliers endpoint"); + } return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); } public List getServices() throws Exception { - String response = apiClient.get("/api/v1/dropdowns/services", String.class); + String response = apiClient.getRawResponse("/api/v1/dropdowns/services"); + if (response == null || response.isEmpty()) { + throw new IllegalStateException("Empty response from services endpoint"); + } return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); } public List getCustomers() throws Exception { - String response = apiClient.get("/api/v1/dropdowns/customers", String.class); + String response = apiClient.getRawResponse("/api/v1/dropdowns/customers"); + if (response == null || response.isEmpty()) { + throw new IllegalStateException("Empty response from customers endpoint"); + } return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); } public List getPets() throws Exception { - String response = apiClient.get("/api/v1/dropdowns/pets", String.class); + String response = apiClient.getRawResponse("/api/v1/dropdowns/pets"); + if (response == null || response.isEmpty()) { + throw new IllegalStateException("Empty response from pets endpoint"); + } return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); } public List getStores() throws Exception { - String response = apiClient.get("/api/v1/dropdowns/stores", String.class); + String response = apiClient.getRawResponse("/api/v1/dropdowns/stores"); + if (response == null || response.isEmpty()) { + throw new IllegalStateException("Empty response from stores endpoint"); + } return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); } } diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/InventoryApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/InventoryApi.java index 1712576e..dbf08be7 100644 --- a/src/main/java/org/example/petshopdesktop/api/endpoints/InventoryApi.java +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/InventoryApi.java @@ -2,9 +2,12 @@ package org.example.petshopdesktop.api.endpoints; import com.fasterxml.jackson.core.type.TypeReference; import org.example.petshopdesktop.api.ApiClient; +import org.example.petshopdesktop.api.dto.common.PageResponse; import org.example.petshopdesktop.api.dto.inventory.InventoryRequest; import org.example.petshopdesktop.api.dto.inventory.InventoryResponse; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.List; public class InventoryApi { @@ -22,10 +25,17 @@ public class InventoryApi { public List listInventory(String query) throws Exception { String path = "/api/v1/inventory?page=0&size=1000"; if (query != null && !query.isEmpty()) { - path += "&q=" + query; + path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8); } - String response = apiClient.get(path, String.class); - return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + String response = apiClient.getRawResponse(path); + PageResponse pageResponse = apiClient.getObjectMapper().readValue( + response, + new TypeReference>() {} + ); + if (pageResponse == null) { + throw new IllegalStateException("Null response from inventory endpoint"); + } + return pageResponse.getContent(); } public InventoryResponse createInventory(InventoryRequest request) throws Exception { diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/PetApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/PetApi.java index 73b2c55c..b5fe23e9 100644 --- a/src/main/java/org/example/petshopdesktop/api/endpoints/PetApi.java +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/PetApi.java @@ -3,9 +3,12 @@ package org.example.petshopdesktop.api.endpoints; import com.fasterxml.jackson.core.type.TypeReference; import org.example.petshopdesktop.api.ApiClient; import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest; +import org.example.petshopdesktop.api.dto.common.PageResponse; import org.example.petshopdesktop.api.dto.pet.PetRequest; import org.example.petshopdesktop.api.dto.pet.PetResponse; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.List; public class PetApi { @@ -23,10 +26,17 @@ public class PetApi { public List listPets(String query) throws Exception { String path = "/api/v1/pets?page=0&size=1000"; if (query != null && !query.isEmpty()) { - path += "&q=" + query; + path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8); } - String response = apiClient.get(path, String.class); - return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + String response = apiClient.getRawResponse(path); + PageResponse pageResponse = apiClient.getObjectMapper().readValue( + response, + new TypeReference>() {} + ); + if (pageResponse == null) { + throw new IllegalStateException("Null response from pets endpoint"); + } + return pageResponse.getContent(); } public PetResponse createPet(PetRequest request) throws Exception { diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/ProductApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/ProductApi.java index 3a40ec76..5bffd489 100644 --- a/src/main/java/org/example/petshopdesktop/api/endpoints/ProductApi.java +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/ProductApi.java @@ -3,9 +3,12 @@ package org.example.petshopdesktop.api.endpoints; import com.fasterxml.jackson.core.type.TypeReference; import org.example.petshopdesktop.api.ApiClient; import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest; +import org.example.petshopdesktop.api.dto.common.PageResponse; import org.example.petshopdesktop.api.dto.product.ProductRequest; import org.example.petshopdesktop.api.dto.product.ProductResponse; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.List; public class ProductApi { @@ -23,10 +26,17 @@ public class ProductApi { public List listProducts(String query) throws Exception { String path = "/api/v1/products?page=0&size=1000"; if (query != null && !query.isEmpty()) { - path += "&q=" + query; + path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8); } - String response = apiClient.get(path, String.class); - return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + String response = apiClient.getRawResponse(path); + PageResponse pageResponse = apiClient.getObjectMapper().readValue( + response, + new TypeReference>() {} + ); + if (pageResponse == null) { + throw new IllegalStateException("Null response from products endpoint"); + } + return pageResponse.getContent(); } public ProductResponse createProduct(ProductRequest request) throws Exception { diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/ProductSupplierApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/ProductSupplierApi.java index b98c3d74..ea65becf 100644 --- a/src/main/java/org/example/petshopdesktop/api/endpoints/ProductSupplierApi.java +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/ProductSupplierApi.java @@ -3,9 +3,12 @@ package org.example.petshopdesktop.api.endpoints; import com.fasterxml.jackson.core.type.TypeReference; import org.example.petshopdesktop.api.ApiClient; import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest; +import org.example.petshopdesktop.api.dto.common.PageResponse; import org.example.petshopdesktop.api.dto.productsupplier.ProductSupplierRequest; import org.example.petshopdesktop.api.dto.productsupplier.ProductSupplierResponse; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.List; public class ProductSupplierApi { @@ -23,10 +26,17 @@ public class ProductSupplierApi { public List listProductSuppliers(String query) throws Exception { String path = "/api/v1/product-suppliers?page=0&size=1000"; if (query != null && !query.isEmpty()) { - path += "&q=" + query; + path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8); } - String response = apiClient.get(path, String.class); - return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + String response = apiClient.getRawResponse(path); + PageResponse pageResponse = apiClient.getObjectMapper().readValue( + response, + new TypeReference>() {} + ); + if (pageResponse == null) { + throw new IllegalStateException("Null response from product-suppliers endpoint"); + } + return pageResponse.getContent(); } public ProductSupplierResponse createProductSupplier(ProductSupplierRequest request) throws Exception { diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/PurchaseOrderApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/PurchaseOrderApi.java index 3b9cd558..accea0eb 100644 --- a/src/main/java/org/example/petshopdesktop/api/endpoints/PurchaseOrderApi.java +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/PurchaseOrderApi.java @@ -2,8 +2,11 @@ package org.example.petshopdesktop.api.endpoints; import com.fasterxml.jackson.core.type.TypeReference; import org.example.petshopdesktop.api.ApiClient; +import org.example.petshopdesktop.api.dto.common.PageResponse; import org.example.petshopdesktop.api.dto.purchaseorder.PurchaseOrderResponse; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.List; public class PurchaseOrderApi { @@ -21,9 +24,16 @@ public class PurchaseOrderApi { public List listPurchaseOrders(String query) throws Exception { String path = "/api/v1/purchase-orders?page=0&size=1000"; if (query != null && !query.isEmpty()) { - path += "&q=" + query; + path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8); } - String response = apiClient.get(path, String.class); - return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + String response = apiClient.getRawResponse(path); + PageResponse pageResponse = apiClient.getObjectMapper().readValue( + response, + new TypeReference>() {} + ); + if (pageResponse == null) { + throw new IllegalStateException("Null response from purchase-orders endpoint"); + } + return pageResponse.getContent(); } } diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/SaleApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/SaleApi.java index f1e18733..d3355012 100644 --- a/src/main/java/org/example/petshopdesktop/api/endpoints/SaleApi.java +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/SaleApi.java @@ -2,9 +2,12 @@ package org.example.petshopdesktop.api.endpoints; import com.fasterxml.jackson.core.type.TypeReference; import org.example.petshopdesktop.api.ApiClient; +import org.example.petshopdesktop.api.dto.common.PageResponse; import org.example.petshopdesktop.api.dto.sale.SaleRequest; import org.example.petshopdesktop.api.dto.sale.SaleResponse; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.List; public class SaleApi { @@ -22,10 +25,17 @@ public class SaleApi { public List listSales(int page, int size, String query) throws Exception { String path = "/api/v1/sales?page=" + page + "&size=" + size; if (query != null && !query.isEmpty()) { - path += "&q=" + query; + path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8); } - String response = apiClient.get(path, String.class); - return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + String response = apiClient.getRawResponse(path); + PageResponse pageResponse = apiClient.getObjectMapper().readValue( + response, + new TypeReference>() {} + ); + if (pageResponse == null) { + throw new IllegalStateException("Null response from sales endpoint"); + } + return pageResponse.getContent(); } public SaleResponse getSale(Long id) throws Exception { diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/ServiceApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/ServiceApi.java index 3ca554f1..66b348dc 100644 --- a/src/main/java/org/example/petshopdesktop/api/endpoints/ServiceApi.java +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/ServiceApi.java @@ -3,9 +3,12 @@ package org.example.petshopdesktop.api.endpoints; import com.fasterxml.jackson.core.type.TypeReference; import org.example.petshopdesktop.api.ApiClient; import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest; +import org.example.petshopdesktop.api.dto.common.PageResponse; import org.example.petshopdesktop.api.dto.service.ServiceRequest; import org.example.petshopdesktop.api.dto.service.ServiceResponse; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.List; public class ServiceApi { @@ -23,10 +26,17 @@ public class ServiceApi { public List listServices(String query) throws Exception { String path = "/api/v1/services?page=0&size=1000"; if (query != null && !query.isEmpty()) { - path += "&q=" + query; + path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8); } - String response = apiClient.get(path, String.class); - return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + String response = apiClient.getRawResponse(path); + PageResponse pageResponse = apiClient.getObjectMapper().readValue( + response, + new TypeReference>() {} + ); + if (pageResponse == null) { + throw new IllegalStateException("Null response from services endpoint"); + } + return pageResponse.getContent(); } public ServiceResponse createService(ServiceRequest request) throws Exception { diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/SupplierApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/SupplierApi.java index 9fe5eaad..bcfb8acb 100644 --- a/src/main/java/org/example/petshopdesktop/api/endpoints/SupplierApi.java +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/SupplierApi.java @@ -3,9 +3,12 @@ package org.example.petshopdesktop.api.endpoints; import com.fasterxml.jackson.core.type.TypeReference; import org.example.petshopdesktop.api.ApiClient; import org.example.petshopdesktop.api.dto.common.BulkDeleteRequest; +import org.example.petshopdesktop.api.dto.common.PageResponse; import org.example.petshopdesktop.api.dto.supplier.SupplierRequest; import org.example.petshopdesktop.api.dto.supplier.SupplierResponse; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.List; public class SupplierApi { @@ -23,10 +26,17 @@ public class SupplierApi { public List listSuppliers(String query) throws Exception { String path = "/api/v1/suppliers?page=0&size=1000"; if (query != null && !query.isEmpty()) { - path += "&q=" + query; + path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8); } - String response = apiClient.get(path, String.class); - return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + String response = apiClient.getRawResponse(path); + PageResponse pageResponse = apiClient.getObjectMapper().readValue( + response, + new TypeReference>() {} + ); + if (pageResponse == null) { + throw new IllegalStateException("Null response from suppliers endpoint"); + } + return pageResponse.getContent(); } public SupplierResponse createSupplier(SupplierRequest request) throws Exception { diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/UserApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/UserApi.java index 54a58c0e..315d53a1 100644 --- a/src/main/java/org/example/petshopdesktop/api/endpoints/UserApi.java +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/UserApi.java @@ -2,9 +2,12 @@ package org.example.petshopdesktop.api.endpoints; import com.fasterxml.jackson.core.type.TypeReference; import org.example.petshopdesktop.api.ApiClient; +import org.example.petshopdesktop.api.dto.common.PageResponse; import org.example.petshopdesktop.api.dto.user.UserRequest; import org.example.petshopdesktop.api.dto.user.UserResponse; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.List; public class UserApi { @@ -22,10 +25,17 @@ public class UserApi { public List listUsers(String query) throws Exception { String path = "/api/v1/users?page=0&size=1000"; if (query != null && !query.isEmpty()) { - path += "&q=" + query; + path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8); } - String response = apiClient.get(path, String.class); - return apiClient.getObjectMapper().readValue(response, new TypeReference>() {}); + String response = apiClient.getRawResponse(path); + PageResponse pageResponse = apiClient.getObjectMapper().readValue( + response, + new TypeReference>() {} + ); + if (pageResponse == null) { + throw new IllegalStateException("Null response from users endpoint"); + } + return pageResponse.getContent(); } public UserResponse createUser(UserRequest request) throws Exception { diff --git a/src/main/java/org/example/petshopdesktop/controllers/LoginController.java b/src/main/java/org/example/petshopdesktop/controllers/LoginController.java index 20e34420..c3162df1 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/LoginController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/LoginController.java @@ -54,17 +54,27 @@ public class LoginController { LoginRequest loginRequest = new LoginRequest(username, password); LoginResponse loginResponse = apiClient.post("/api/v1/auth/login", loginRequest, LoginResponse.class); + if (loginResponse == null) { + throw new IllegalStateException("Login response is null"); + } + String token = loginResponse.getToken(); String roleStr = loginResponse.getRole(); + if (token == null || roleStr == null) { + throw new IllegalStateException("Token or role is null"); + } Role role = Role.valueOf(roleStr.toUpperCase()); UserSession.getInstance().login(null, username, role, token); UserInfoResponse userInfo = apiClient.get("/api/v1/auth/me", UserInfoResponse.class); + if (userInfo == null) { + throw new IllegalStateException("User info is null"); + } UserSession.getInstance().login(userInfo.getId(), username, role, token); List stores = DropdownApi.getInstance().getStores(); - if (!stores.isEmpty()) { + if (stores != null && !stores.isEmpty()) { UserSession.getInstance().setStoreId(stores.get(0).getId()); } diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/AdoptionDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/AdoptionDialogController.java index ed1fca7c..a1ed25fb 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/AdoptionDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/AdoptionDialogController.java @@ -67,8 +67,10 @@ public class AdoptionDialogController { try { List pets = DropdownApi.getInstance().getPets(); Platform.runLater(() -> { - ObservableList petsObs = FXCollections.observableArrayList(pets); - cbPet.setItems(petsObs); + if (pets != null) { + ObservableList petsObs = FXCollections.observableArrayList(pets); + cbPet.setItems(petsObs); + } }); } catch (Exception e) { Platform.runLater(() -> { @@ -85,8 +87,10 @@ public class AdoptionDialogController { try { List customers = DropdownApi.getInstance().getCustomers(); Platform.runLater(() -> { - ObservableList customersObs = FXCollections.observableArrayList(customers); - cbCustomer.setItems(customersObs); + if (customers != null) { + ObservableList customersObs = FXCollections.observableArrayList(customers); + cbCustomer.setItems(customersObs); + } }); } catch (Exception e) { Platform.runLater(() -> { @@ -144,7 +148,11 @@ public class AdoptionDialogController { if (mode.equals("Add")) { AdoptionApi.getInstance().createAdoption(request); } else { - Long adoptionId = Long.parseLong(lblAdoptionId.getText().split(": ")[1]); + String[] parts = lblAdoptionId.getText().split(": "); + if (parts.length < 2) { + throw new IllegalStateException("Invalid adoption ID format"); + } + Long adoptionId = Long.parseLong(parts[1]); AdoptionApi.getInstance().updateAdoption(adoptionId, request); } @@ -197,7 +205,14 @@ public class AdoptionDialogController { } if (adoption.getAdoptionDate() != null && !adoption.getAdoptionDate().isEmpty()) { - dpAdoptionDate.setValue(LocalDate.parse(adoption.getAdoptionDate())); + try { + dpAdoptionDate.setValue(LocalDate.parse(adoption.getAdoptionDate())); + } catch (Exception e) { + ActivityLogger.getInstance().logException( + "AdoptionDialogController.displayAdoptionDetails", + e, + "Parsing adoption date"); + } } for (String status : cbAdoptionStatus.getItems()) { diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/AppointmentDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/AppointmentDialogController.java index ecefa73c..f0db4368 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/AppointmentDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/AppointmentDialogController.java @@ -80,9 +80,15 @@ public class AppointmentDialogController { List pets = DropdownApi.getInstance().getPets(); Platform.runLater(() -> { - cbService.setItems(FXCollections.observableArrayList(services)); - cbCustomer.setItems(FXCollections.observableArrayList(customers)); - cbPet.setItems(FXCollections.observableArrayList(pets)); + if (services != null) { + cbService.setItems(FXCollections.observableArrayList(services)); + } + if (customers != null) { + cbCustomer.setItems(FXCollections.observableArrayList(customers)); + } + if (pets != null) { + cbPet.setItems(FXCollections.observableArrayList(pets)); + } }); } catch (Exception e) { Platform.runLater(() -> { @@ -163,15 +169,29 @@ public class AppointmentDialogController { selectedAppointment = appt; lblAppointmentId.setText("ID: " + appt.getAppointmentId()); - dpAppointmentDate.setValue( - java.time.LocalDate.parse(appt.getAppointmentDate()) - ); + try { + dpAppointmentDate.setValue( + java.time.LocalDate.parse(appt.getAppointmentDate()) + ); + } catch (Exception e) { + ActivityLogger.getInstance().logException( + "AppointmentDialogController.displayAppointmentDetails", + e, + "Parsing appointment date"); + } cbAppointmentStatus.setValue(appt.getAppointmentStatus()); - LocalTime time = LocalTime.parse(appt.getAppointmentTime()); - cbHour.setValue(time.getHour()); - cbMinute.setValue(time.getMinute()); + try { + LocalTime time = LocalTime.parse(appt.getAppointmentTime()); + cbHour.setValue(time.getHour()); + cbMinute.setValue(time.getMinute()); + } catch (Exception e) { + ActivityLogger.getInstance().logException( + "AppointmentDialogController.displayAppointmentDetails", + e, + "Parsing appointment time"); + } cbService.getItems().forEach(s -> { if (s.getId() == appt.getServiceId()) cbService.setValue(s); diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/InventoryDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/InventoryDialogController.java index fd594c18..3a0b1518 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/InventoryDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/InventoryDialogController.java @@ -70,17 +70,19 @@ public class InventoryDialogController { //Load product list from API into combobox try { List productResponses = ProductApi.getInstance().listProducts(null); - ObservableList products = FXCollections.observableArrayList(); - for (ProductResponse pr : productResponses) { - products.add(new Product( - pr.getId().intValue(), - pr.getProductName(), - pr.getPrice().doubleValue(), - 0, - pr.getDescription() - )); + if (productResponses != null) { + ObservableList products = FXCollections.observableArrayList(); + for (ProductResponse pr : productResponses) { + products.add(new Product( + pr.getId().intValue(), + pr.getProductName(), + pr.getPrice().doubleValue(), + 0, + pr.getDescription() + )); + } + cbProduct.setItems(products); } - cbProduct.setItems(products); } catch (Exception e) { ActivityLogger.getInstance().logException( "InventoryDialogController.initialize", @@ -126,12 +128,22 @@ public class InventoryDialogController { InventoryRequest request = new InventoryRequest(); Product selectedProduct = cbProduct.getSelectionModel().getSelectedItem(); request.setProductId((long) selectedProduct.getProdId()); - request.setStockQuantity(Integer.parseInt(txtQuantity.getText())); + int quantity; + try { + quantity = Integer.parseInt(txtQuantity.getText()); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Invalid quantity format"); + } + request.setStockQuantity(quantity); if (mode.equals("Add")) { InventoryApi.getInstance().createInventory(request); } else { - Long inventoryId = Long.parseLong(lblInventoryId.getText().split(": ")[1]); + String[] parts = lblInventoryId.getText().split(": "); + if (parts.length < 2) { + throw new IllegalStateException("Invalid inventory ID format"); + } + Long inventoryId = Long.parseLong(parts[1]); InventoryApi.getInstance().updateInventory(inventoryId, request); } diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/PetDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/PetDialogController.java index d41790dc..1ea93d3e 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/PetDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/PetDialogController.java @@ -107,7 +107,11 @@ public class PetDialogController { if(mode.equals("Add")) { PetApi.getInstance().createPet(request); } else { - Long petId = Long.parseLong(lblPetId.getText().split(": ")[1]); + String[] parts = lblPetId.getText().split(": "); + if (parts.length < 2) { + throw new IllegalStateException("Invalid pet ID format"); + } + Long petId = Long.parseLong(parts[1]); PetApi.getInstance().updatePet(petId, request); } @@ -142,9 +146,18 @@ public class PetDialogController { request.setSpecies(txtPetSpecies.getText()); request.setBreed(txtPetBreed.getText()); request.setPetStatus(cbPetStatus.getValue()); - request.setPrice(new BigDecimal(txtPetPrice.getText())); + try { + request.setPrice(new BigDecimal(txtPetPrice.getText())); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Invalid price format"); + } - int age = Integer.parseInt(txtPetAge.getText()); + int age; + try { + age = Integer.parseInt(txtPetAge.getText()); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Invalid age format"); + } LocalDate dateOfBirth = LocalDate.now().minusYears(age); request.setDateOfBirth(dateOfBirth); diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductDialogController.java index 298478aa..b35cd57e 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductDialogController.java @@ -70,14 +70,16 @@ public class ProductDialogController { //Set up combobox for selecting category try { List categories = DropdownApi.getInstance().getCategories(); - ObservableList categoriesObs = FXCollections.observableArrayList(categories); - cbProdCategory.setItems(categoriesObs); + if (categories != null) { + ObservableList categoriesObs = FXCollections.observableArrayList(categories); + cbProdCategory.setItems(categoriesObs); + } } catch (Exception e) { ActivityLogger.getInstance().logException( "ProductDialogController.initialize", e, "Loading categories for combo box"); - throw new RuntimeException(e); + System.out.println("Error loading categories: " + e.getMessage()); } } @@ -110,14 +112,24 @@ public class ProductDialogController { try { ProductRequest request = new ProductRequest(); request.setProductName(txtProdName.getText()); - request.setPrice(new BigDecimal(txtProdPrice.getText())); + BigDecimal price; + try { + price = new BigDecimal(txtProdPrice.getText()); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Invalid price format"); + } + request.setPrice(price); request.setCategoryId(cbProdCategory.getSelectionModel().getSelectedItem().getId()); request.setDescription(txtProdDesc.getText()); if (mode.equals("Add")) { ProductApi.getInstance().createProduct(request); } else { - Long productId = Long.parseLong(lblProdId.getText().split(": ")[1]); + String[] parts = lblProdId.getText().split(": "); + if (parts.length < 2) { + throw new IllegalStateException("Invalid product ID format"); + } + Long productId = Long.parseLong(parts[1]); ProductApi.getInstance().updateProduct(productId, request); } diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductSupplierDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductSupplierDialogController.java index a94a6012..3b67fc54 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductSupplierDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductSupplierDialogController.java @@ -119,8 +119,12 @@ public class ProductSupplierDialogController { var products = DropdownApi.getInstance().getProducts(); Platform.runLater(() -> { - cbSupplier.setItems(FXCollections.observableArrayList(suppliers)); - cbProduct.setItems(FXCollections.observableArrayList(products)); + if (suppliers != null) { + cbSupplier.setItems(FXCollections.observableArrayList(suppliers)); + } + if (products != null) { + cbProduct.setItems(FXCollections.observableArrayList(products)); + } }); } catch (Exception e) { Platform.runLater(() -> { @@ -204,7 +208,11 @@ public class ProductSupplierDialogController { ProductSupplierRequest request = new ProductSupplierRequest(); request.setSupplierId(cbSupplier.getSelectionModel().getSelectedItem().getId()); request.setProductId(cbProduct.getSelectionModel().getSelectedItem().getId()); - request.setSupplierPrice(new BigDecimal(txtCost.getText())); + try { + request.setSupplierPrice(new BigDecimal(txtCost.getText())); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Invalid cost format"); + } return request; } diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/SupplierDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/SupplierDialogController.java index 18dab623..b54e3b31 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/SupplierDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/SupplierDialogController.java @@ -99,7 +99,11 @@ public class SupplierDialogController { if (mode.equals("Add")) { SupplierApi.getInstance().createSupplier(request); } else { - Long supplierId = Long.parseLong(lblSupId.getText().split(": ")[1]); + String[] parts = lblSupId.getText().split(": "); + if (parts.length < 2) { + throw new IllegalStateException("Invalid supplier ID format"); + } + Long supplierId = Long.parseLong(parts[1]); SupplierApi.getInstance().updateSupplier(supplierId, request); } From d4e532a798891a745dada3ecee65c1216ae869c9 Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Sun, 8 Mar 2026 22:01:10 -0600 Subject: [PATCH 13/19] Fix desktop ProductSupplier to use composite keys - Remove id field from ProductSupplierResponse - Rename supplierPrice to cost in ProductSupplierResponse and ProductSupplierRequest - Update ProductSupplierApi to use composite keys (productId, supplierId) for update and delete - Update ProductSupplierController delete logic to iterate and delete with composite keys - Update ProductSupplierController mapping to use getCost() instead of getSupplierPrice() - Update ProductSupplierDialogController to pass both productId and supplierId to update - Update ProductSupplierDialogController to use setCost() instead of setSupplierPrice() - Remove unused selectedId field from ProductSupplierDialogController --- log.txt | 67 +++++++++++++++++++ .../api/dto/adoption/AdoptionRequest.java | 3 + .../api/dto/adoption/AdoptionResponse.java | 3 + .../api/dto/analytics/DailySales.java | 3 + .../api/dto/analytics/DashboardResponse.java | 3 + .../api/dto/analytics/TopProduct.java | 3 + .../dto/appointment/AppointmentRequest.java | 3 + .../dto/appointment/AppointmentResponse.java | 3 + .../api/dto/auth/LoginResponse.java | 3 + .../api/dto/auth/UserInfoResponse.java | 3 + .../api/dto/common/DropdownOption.java | 3 + .../api/dto/common/PageResponse.java | 12 ++++ .../api/dto/inventory/InventoryRequest.java | 3 + .../api/dto/inventory/InventoryResponse.java | 3 + .../api/dto/pet/PetRequest.java | 3 + .../api/dto/pet/PetResponse.java | 3 + .../api/dto/product/ProductRequest.java | 3 + .../api/dto/product/ProductResponse.java | 3 + .../ProductSupplierRequest.java | 13 ++-- .../ProductSupplierResponse.java | 18 ++--- .../purchaseorder/PurchaseOrderResponse.java | 3 + .../api/dto/sale/SaleItemRequest.java | 3 + .../api/dto/sale/SaleItemResponse.java | 3 + .../api/dto/sale/SaleRequest.java | 3 + .../api/dto/sale/SaleResponse.java | 3 + .../api/dto/service/ServiceRequest.java | 3 + .../api/dto/service/ServiceResponse.java | 3 + .../api/dto/supplier/SupplierRequest.java | 3 + .../api/dto/supplier/SupplierResponse.java | 3 + .../api/dto/user/UserRequest.java | 3 + .../api/dto/user/UserResponse.java | 3 + .../api/endpoints/ProductSupplierApi.java | 8 +-- .../ProductSupplierController.java | 40 +++++++---- .../ProductSupplierDialogController.java | 6 +- 34 files changed, 206 insertions(+), 39 deletions(-) diff --git a/log.txt b/log.txt index d142919d..485318d5 100644 --- a/log.txt +++ b/log.txt @@ -49,3 +49,70 @@ The last packet sent successfully to the server was 0 milliseconds ago. The driv at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 1] | Context: Authentication attempt for username: staff [2026-03-07 17:50:34] [ERROR] EXCEPTION | Location: LoginController.btnLoginClicked | Type: MismatchedInputException | Message: Cannot deserialize value of type `java.lang.String` from Array value (token `JsonToken.START_ARRAY`) at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 1] | Context: Authentication attempt for username: staff +[2026-03-07 17:55:02] [ERROR] EXCEPTION | Location: LoginController.btnLoginClicked | Type: MismatchedInputException | Message: Cannot deserialize value of type `java.lang.String` from Array value (token `JsonToken.START_ARRAY`) + at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 1] | Context: Authentication attempt for username: staff +[2026-03-07 17:55:16] [ERROR] EXCEPTION | Location: LoginController.btnLoginClicked | Type: MismatchedInputException | Message: Cannot deserialize value of type `java.lang.String` from Array value (token `JsonToken.START_ARRAY`) + at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 1] | Context: Authentication attempt for username: staff +[2026-03-07 18:11:05] [ERROR] EXCEPTION | Location: LoginController.btnLoginClicked | Type: ConnectException | Message: null | Context: Authentication attempt for username: staff +[2026-03-07 18:11:42] [ERROR] EXCEPTION | Location: LoginController.btnLoginClicked | Type: RuntimeException | Message: Authentication failed. Please log in again. | Context: Authentication attempt for username: staff +[2026-03-07 18:11:48] [ERROR] EXCEPTION | Location: AnalyticsController.loadAnalyticsData | Type: RuntimeException | Message: Access restricted. You don't have permission to perform this action. | Context: Loading analytics data +[2026-03-07 18:11:52] [ERROR] EXCEPTION | Location: SaleController.setupCreateSale | Type: MismatchedInputException | Message: Cannot deserialize value of type `java.util.ArrayList` from Object value (token `JsonToken.START_OBJECT`) + at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 1] | Context: Loading products +[2026-03-07 18:11:52] [ERROR] EXCEPTION | Location: SaleController.refreshSales | Type: MismatchedInputException | Message: Cannot deserialize value of type `java.util.ArrayList` from Object value (token `JsonToken.START_OBJECT`) + at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 1] | Context: Loading sales +[2026-03-07 18:11:53] [ERROR] EXCEPTION | Location: AppointmentController.loadAppointments | Type: MismatchedInputException | Message: Cannot deserialize value of type `java.util.ArrayList` from Object value (token `JsonToken.START_OBJECT`) + at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 1] | Context: Loading appointments for table display +[2026-03-07 18:11:53] [ERROR] EXCEPTION | Location: ServiceController.displayServices | Type: MismatchedInputException | Message: Cannot deserialize value of type `java.util.ArrayList` from Object value (token `JsonToken.START_OBJECT`) + at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 1] | Context: Fetching service data for table display +[2026-03-07 18:11:54] [ERROR] EXCEPTION | Location: ServiceController.displayServices | Type: MismatchedInputException | Message: Cannot deserialize value of type `java.util.ArrayList` from Object value (token `JsonToken.START_OBJECT`) + at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 1] | Context: Fetching service data for table display +[2026-03-07 18:11:56] [ERROR] EXCEPTION | Location: PetController.displayPets | Type: MismatchedInputException | Message: Cannot deserialize value of type `java.util.ArrayList` from Object value (token `JsonToken.START_OBJECT`) + at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 1] | Context: Fetching pet data for table display +[2026-03-07 18:11:56] [ERROR] EXCEPTION | Location: PetController.displayPets | Type: MismatchedInputException | Message: Cannot deserialize value of type `java.util.ArrayList` from Object value (token `JsonToken.START_OBJECT`) + at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 1] | Context: Fetching pet data for table display +[2026-03-07 18:11:56] [ERROR] EXCEPTION | Location: AdoptionController.displayAdoptions | Type: MismatchedInputException | Message: Cannot deserialize value of type `java.util.ArrayList` from Object value (token `JsonToken.START_OBJECT`) + at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 1] | Context: Fetching adoption data for table display +[2026-03-07 18:11:57] [ERROR] EXCEPTION | Location: ProductController.displayProduct | Type: MismatchedInputException | Message: Cannot deserialize value of type `java.util.ArrayList` from Object value (token `JsonToken.START_OBJECT`) + at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 1] | Context: Fetching product data for table display +[2026-03-07 18:11:58] [ERROR] EXCEPTION | Location: AnalyticsController.loadAnalyticsData | Type: RuntimeException | Message: Access restricted. You don't have permission to perform this action. | Context: Loading analytics data +[2026-03-07 18:47:48] [ERROR] EXCEPTION | Location: AnalyticsController.loadAnalyticsData | Type: RuntimeException | Message: Access restricted. You don't have permission to perform this action. | Context: Loading analytics data +[2026-03-07 18:48:01] [ERROR] EXCEPTION | Location: AnalyticsController.loadAnalyticsData | Type: RuntimeException | Message: Access restricted. You don't have permission to perform this action. | Context: Loading analytics data +[2026-03-07 18:48:05] [ERROR] EXCEPTION | Location: AnalyticsController.loadAnalyticsData | Type: RuntimeException | Message: Access restricted. You don't have permission to perform this action. | Context: Loading analytics data +[2026-03-07 18:48:05] [ERROR] EXCEPTION | Location: AnalyticsController.loadAnalyticsData | Type: RuntimeException | Message: Access restricted. You don't have permission to perform this action. | Context: Loading analytics data +[2026-03-07 18:51:14] [ERROR] EXCEPTION | Location: AnalyticsController.loadAnalyticsData | Type: RuntimeException | Message: Access restricted. You don't have permission to perform this action. | Context: Loading analytics data +[2026-03-07 18:51:14] [ERROR] EXCEPTION | Location: AnalyticsController.loadAnalyticsData | Type: RuntimeException | Message: Access restricted. You don't have permission to perform this action. | Context: Loading analytics data +[2026-03-07 18:51:28] [ERROR] EXCEPTION | Location: AnalyticsController.loadAnalyticsData | Type: RuntimeException | Message: Access restricted. You don't have permission to perform this action. | Context: Loading analytics data +[2026-03-07 18:51:30] [ERROR] EXCEPTION | Location: AnalyticsController.loadAnalyticsData | Type: RuntimeException | Message: Access restricted. You don't have permission to perform this action. | Context: Loading analytics data +[2026-03-08 10:03:43] [ERROR] EXCEPTION | Location: SaleController.setupCreateSale | Type: NullPointerException | Message: Cannot invoke "java.lang.Long.intValue()" because the return value of "org.example.petshopdesktop.api.dto.product.ProductResponse.getId()" is null | Context: Loading products +[2026-03-08 10:03:43] [ERROR] EXCEPTION | Location: SaleController.refreshSales | Type: NullPointerException | Message: Cannot invoke "java.lang.Long.intValue()" because the return value of "org.example.petshopdesktop.api.dto.sale.SaleResponse.getId()" is null | Context: Loading sales +[2026-03-08 10:03:44] [ERROR] EXCEPTION | Location: AppointmentController.loadAppointments | Type: MismatchedInputException | Message: Cannot deserialize value of type `java.lang.String` from Array value (token `JsonToken.START_ARRAY`) + at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 219] (through reference chain: org.example.petshopdesktop.api.dto.common.PageResponse["content"]->java.util.ArrayList[0]->org.example.petshopdesktop.api.dto.appointment.AppointmentResponse["petNames"]) | Context: Loading appointments for table display +[2026-03-08 10:03:44] [ERROR] EXCEPTION | Location: ServiceController.displayServices | Type: NullPointerException | Message: Cannot invoke "java.lang.Long.intValue()" because the return value of "org.example.petshopdesktop.api.dto.service.ServiceResponse.getId()" is null | Context: Fetching service data for table display +[2026-03-08 10:03:45] [ERROR] EXCEPTION | Location: ServiceController.displayServices | Type: NullPointerException | Message: Cannot invoke "java.lang.Long.intValue()" because the return value of "org.example.petshopdesktop.api.dto.service.ServiceResponse.getId()" is null | Context: Fetching service data for table display +[2026-03-08 10:03:46] [ERROR] EXCEPTION | Location: PetController.displayPets | Type: NullPointerException | Message: Cannot invoke "java.lang.Long.intValue()" because the return value of "org.example.petshopdesktop.api.dto.pet.PetResponse.getId()" is null | Context: Fetching pet data for table display +[2026-03-08 10:03:46] [ERROR] EXCEPTION | Location: AdoptionController.displayAdoptions | Type: NullPointerException | Message: Cannot invoke "java.lang.Long.intValue()" because the return value of "org.example.petshopdesktop.api.dto.adoption.AdoptionResponse.getId()" is null | Context: Fetching adoption data for table display +[2026-03-08 10:03:47] [ERROR] EXCEPTION | Location: AdoptionController.displayAdoptions | Type: NullPointerException | Message: Cannot invoke "java.lang.Long.intValue()" because the return value of "org.example.petshopdesktop.api.dto.adoption.AdoptionResponse.getId()" is null | Context: Fetching adoption data for table display +[2026-03-08 10:03:47] [ERROR] EXCEPTION | Location: ProductController.displayProduct | Type: NullPointerException | Message: Cannot invoke "java.lang.Long.intValue()" because the return value of "org.example.petshopdesktop.api.dto.product.ProductResponse.getId()" is null | Context: Fetching product data for table display +[2026-03-08 10:03:48] [ERROR] EXCEPTION | Location: InventoryController.displayInventory | Type: NullPointerException | Message: Cannot invoke "java.lang.Long.intValue()" because the return value of "org.example.petshopdesktop.api.dto.inventory.InventoryResponse.getId()" is null | Context: Fetching inventory data for table display +[2026-03-08 10:03:48] [ERROR] EXCEPTION | Location: ProductSupplierController.displayProductSupplier | Type: NullPointerException | Message: Cannot invoke "java.math.BigDecimal.doubleValue()" because the return value of "org.example.petshopdesktop.api.dto.productsupplier.ProductSupplierResponse.getSupplierPrice()" is null | Context: Fetching product-supplier data for table display +[2026-03-08 10:03:49] [ERROR] EXCEPTION | Location: SupplierController.displaySupplier | Type: NullPointerException | Message: Cannot invoke "java.lang.Long.intValue()" because the return value of "org.example.petshopdesktop.api.dto.supplier.SupplierResponse.getId()" is null | Context: Fetching supplier data for table display +[2026-03-08 10:03:50] [ERROR] EXCEPTION | Location: PurchaseOrderController.loadPurchaseOrders | Type: NullPointerException | Message: Cannot invoke "java.lang.Long.longValue()" because the return value of "org.example.petshopdesktop.api.dto.purchaseorder.PurchaseOrderResponse.getId()" is null | Context: Loading purchase orders for table display +[2026-03-08 10:04:02] [ERROR] EXCEPTION | Location: SaleController.setupCreateSale | Type: NullPointerException | Message: Cannot invoke "java.lang.Long.intValue()" because the return value of "org.example.petshopdesktop.api.dto.product.ProductResponse.getId()" is null | Context: Loading products +[2026-03-08 10:04:02] [ERROR] EXCEPTION | Location: SaleController.refreshSales | Type: NullPointerException | Message: Cannot invoke "java.lang.Long.intValue()" because the return value of "org.example.petshopdesktop.api.dto.sale.SaleResponse.getId()" is null | Context: Loading sales +[2026-03-08 10:04:03] [ERROR] EXCEPTION | Location: SaleController.refreshSales | Type: NullPointerException | Message: Cannot invoke "java.lang.Long.intValue()" because the return value of "org.example.petshopdesktop.api.dto.sale.SaleResponse.getId()" is null | Context: Loading sales +[2026-03-08 10:05:41] [ERROR] EXCEPTION | Location: AnalyticsController.loadAnalyticsData | Type: RuntimeException | Message: Access restricted. You don't have permission to perform this action. | Context: Loading analytics data +[2026-03-08 10:05:44] [ERROR] EXCEPTION | Location: AnalyticsController.loadAnalyticsData | Type: RuntimeException | Message: Access restricted. You don't have permission to perform this action. | Context: Loading analytics data +[2026-03-08 10:05:46] [ERROR] EXCEPTION | Location: SaleController.setupCreateSale | Type: NullPointerException | Message: Cannot invoke "java.lang.Long.intValue()" because the return value of "org.example.petshopdesktop.api.dto.product.ProductResponse.getId()" is null | Context: Loading products +[2026-03-08 10:05:46] [ERROR] EXCEPTION | Location: SaleController.refreshSales | Type: NullPointerException | Message: Cannot invoke "java.lang.Long.intValue()" because the return value of "org.example.petshopdesktop.api.dto.sale.SaleResponse.getId()" is null | Context: Loading sales +[2026-03-08 10:05:47] [ERROR] EXCEPTION | Location: SaleController.setupCreateSale | Type: NullPointerException | Message: Cannot invoke "java.lang.Long.intValue()" because the return value of "org.example.petshopdesktop.api.dto.product.ProductResponse.getId()" is null | Context: Loading products +[2026-03-08 10:05:47] [ERROR] EXCEPTION | Location: SaleController.refreshSales | Type: NullPointerException | Message: Cannot invoke "java.lang.Long.intValue()" because the return value of "org.example.petshopdesktop.api.dto.sale.SaleResponse.getId()" is null | Context: Loading sales +[2026-03-08 10:05:47] [ERROR] EXCEPTION | Location: AppointmentController.loadAppointments | Type: MismatchedInputException | Message: Cannot deserialize value of type `java.lang.String` from Array value (token `JsonToken.START_ARRAY`) + at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 219] (through reference chain: org.example.petshopdesktop.api.dto.common.PageResponse["content"]->java.util.ArrayList[0]->org.example.petshopdesktop.api.dto.appointment.AppointmentResponse["petNames"]) | Context: Loading appointments for table display +[2026-03-08 10:05:48] [ERROR] EXCEPTION | Location: AppointmentController.loadAppointments | Type: MismatchedInputException | Message: Cannot deserialize value of type `java.lang.String` from Array value (token `JsonToken.START_ARRAY`) + at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 219] (through reference chain: org.example.petshopdesktop.api.dto.common.PageResponse["content"]->java.util.ArrayList[0]->org.example.petshopdesktop.api.dto.appointment.AppointmentResponse["petNames"]) | Context: Loading appointments for table display +[2026-03-08 10:12:33] [ERROR] EXCEPTION | Location: LoginController.btnLoginClicked | Type: ConnectException | Message: null | Context: Authentication attempt for username: admin +[2026-03-08 10:55:59] [ERROR] EXCEPTION | Location: AnalyticsController.loadAnalyticsData | Type: RuntimeException | Message: Access restricted. You don't have permission to perform this action. | Context: Loading analytics data +[2026-03-08 10:56:02] [ERROR] EXCEPTION | Location: SaleController.setupCreateSale | Type: NullPointerException | Message: Cannot invoke "java.lang.Long.intValue()" because the return value of "org.example.petshopdesktop.api.dto.product.ProductResponse.getId()" is null | Context: Loading products +[2026-03-08 10:56:02] [ERROR] EXCEPTION | Location: SaleController.refreshSales | Type: NullPointerException | Message: Cannot invoke "java.lang.Long.intValue()" because the return value of "org.example.petshopdesktop.api.dto.sale.SaleResponse.getId()" is null | Context: Loading sales +[2026-03-08 10:56:04] [ERROR] EXCEPTION | Location: ServiceController.displayServices | Type: NullPointerException | Message: Cannot invoke "java.lang.Long.intValue()" because the return value of "org.example.petshopdesktop.api.dto.service.ServiceResponse.getId()" is null | Context: Fetching service data for table display +[2026-03-08 10:56:04] [ERROR] EXCEPTION | Location: PetController.displayPets | Type: NullPointerException | Message: Cannot invoke "java.lang.Long.intValue()" because the return value of "org.example.petshopdesktop.api.dto.pet.PetResponse.getId()" is null | Context: Fetching pet data for table display diff --git a/src/main/java/org/example/petshopdesktop/api/dto/adoption/AdoptionRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/adoption/AdoptionRequest.java index 230d5413..5bea7090 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/adoption/AdoptionRequest.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/adoption/AdoptionRequest.java @@ -8,6 +8,9 @@ public class AdoptionRequest { private LocalDate adoptionDate; private String adoptionStatus; + public AdoptionRequest() { + } + public Long getPetId() { return petId; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/adoption/AdoptionResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/adoption/AdoptionResponse.java index 2466a287..151a76da 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/adoption/AdoptionResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/adoption/AdoptionResponse.java @@ -9,6 +9,9 @@ public class AdoptionResponse { private LocalDate adoptionDate; private String adoptionStatus; + public AdoptionResponse() { + } + public Long getId() { return id; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/analytics/DailySales.java b/src/main/java/org/example/petshopdesktop/api/dto/analytics/DailySales.java index 602fc8be..5c249452 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/analytics/DailySales.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/analytics/DailySales.java @@ -7,6 +7,9 @@ public class DailySales { private LocalDate date; private BigDecimal totalSales; + public DailySales() { + } + public LocalDate getDate() { return date; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/analytics/DashboardResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/analytics/DashboardResponse.java index 0618419b..0497f48e 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/analytics/DashboardResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/analytics/DashboardResponse.java @@ -11,6 +11,9 @@ public class DashboardResponse { private List dailySales; private List topProducts; + public DashboardResponse() { + } + public BigDecimal getTotalRevenue() { return totalRevenue; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/analytics/TopProduct.java b/src/main/java/org/example/petshopdesktop/api/dto/analytics/TopProduct.java index bc63265a..29c1f7f6 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/analytics/TopProduct.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/analytics/TopProduct.java @@ -7,6 +7,9 @@ public class TopProduct { private Integer quantitySold; private BigDecimal totalRevenue; + public TopProduct() { + } + public String getProductName() { return productName; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/appointment/AppointmentRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/appointment/AppointmentRequest.java index e675834c..fe4f7faa 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/appointment/AppointmentRequest.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/appointment/AppointmentRequest.java @@ -12,6 +12,9 @@ public class AppointmentRequest { private LocalTime appointmentTime; private String appointmentStatus; + public AppointmentRequest() { + } + public List getPetIds() { return petIds; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/appointment/AppointmentResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/appointment/AppointmentResponse.java index bbe42bd1..5c9415d0 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/appointment/AppointmentResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/appointment/AppointmentResponse.java @@ -12,6 +12,9 @@ public class AppointmentResponse { private LocalTime appointmentTime; private String appointmentStatus; + public AppointmentResponse() { + } + public Long getId() { return id; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/auth/LoginResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/auth/LoginResponse.java index 18eb8449..50354d48 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/auth/LoginResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/auth/LoginResponse.java @@ -5,6 +5,9 @@ public class LoginResponse { private String username; private String role; + public LoginResponse() { + } + public String getToken() { return token; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/auth/UserInfoResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/auth/UserInfoResponse.java index 35192de5..16ee1204 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/auth/UserInfoResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/auth/UserInfoResponse.java @@ -5,6 +5,9 @@ public class UserInfoResponse { private String username; private String role; + public UserInfoResponse() { + } + public Long getId() { return id; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/common/DropdownOption.java b/src/main/java/org/example/petshopdesktop/api/dto/common/DropdownOption.java index b1f24b9c..08678e53 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/common/DropdownOption.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/common/DropdownOption.java @@ -4,6 +4,9 @@ public class DropdownOption { private Long id; private String label; + public DropdownOption() { + } + public Long getId() { return id; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/common/PageResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/common/PageResponse.java index 9676a55d..bbcc467c 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/common/PageResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/common/PageResponse.java @@ -1,15 +1,27 @@ package org.example.petshopdesktop.api.dto.common; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + import java.util.List; +@JsonIgnoreProperties(ignoreUnknown = true) public class PageResponse { private List content; + + @JsonProperty("number") private int pageNumber; + + @JsonProperty("size") private int pageSize; + private long totalElements; private int totalPages; private boolean last; + public PageResponse() { + } + public List getContent() { return content; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/inventory/InventoryRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/inventory/InventoryRequest.java index 4eb99cd0..03abd005 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/inventory/InventoryRequest.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/inventory/InventoryRequest.java @@ -6,6 +6,9 @@ public class InventoryRequest { private Integer stockQuantity; private Integer reorderLevel; + public InventoryRequest() { + } + public Long getProductId() { return productId; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/inventory/InventoryResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/inventory/InventoryResponse.java index 7a9ac8b7..15250c74 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/inventory/InventoryResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/inventory/InventoryResponse.java @@ -8,6 +8,9 @@ public class InventoryResponse { private Integer stockQuantity; private Integer reorderLevel; + public InventoryResponse() { + } + public Long getId() { return id; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/pet/PetRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/pet/PetRequest.java index a67d3e45..78a9ebfb 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/pet/PetRequest.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/pet/PetRequest.java @@ -13,6 +13,9 @@ public class PetRequest { private BigDecimal price; private String petStatus; + public PetRequest() { + } + public String getPetName() { return petName; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/pet/PetResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/pet/PetResponse.java index 5565e583..f865e58d 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/pet/PetResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/pet/PetResponse.java @@ -14,6 +14,9 @@ public class PetResponse { private BigDecimal price; private String petStatus; + public PetResponse() { + } + public Long getId() { return id; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/product/ProductRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/product/ProductRequest.java index a51ee4d0..7591a279 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/product/ProductRequest.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/product/ProductRequest.java @@ -8,6 +8,9 @@ public class ProductRequest { private BigDecimal price; private String description; + public ProductRequest() { + } + public String getProductName() { return productName; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/product/ProductResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/product/ProductResponse.java index 07efa236..11f84b1f 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/product/ProductResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/product/ProductResponse.java @@ -9,6 +9,9 @@ public class ProductResponse { private BigDecimal price; private String description; + public ProductResponse() { + } + public Long getId() { return id; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/productsupplier/ProductSupplierRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/productsupplier/ProductSupplierRequest.java index e57d3801..69f4ad61 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/productsupplier/ProductSupplierRequest.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/productsupplier/ProductSupplierRequest.java @@ -5,7 +5,10 @@ import java.math.BigDecimal; public class ProductSupplierRequest { private Long productId; private Long supplierId; - private BigDecimal supplierPrice; + private BigDecimal cost; + + public ProductSupplierRequest() { + } public Long getProductId() { return productId; @@ -23,11 +26,11 @@ public class ProductSupplierRequest { this.supplierId = supplierId; } - public BigDecimal getSupplierPrice() { - return supplierPrice; + public BigDecimal getCost() { + return cost; } - public void setSupplierPrice(BigDecimal supplierPrice) { - this.supplierPrice = supplierPrice; + public void setCost(BigDecimal cost) { + this.cost = cost; } } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/productsupplier/ProductSupplierResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/productsupplier/ProductSupplierResponse.java index 55478763..b601efe3 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/productsupplier/ProductSupplierResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/productsupplier/ProductSupplierResponse.java @@ -3,19 +3,13 @@ package org.example.petshopdesktop.api.dto.productsupplier; import java.math.BigDecimal; public class ProductSupplierResponse { - private Long id; private Long productId; private Long supplierId; private String productName; private String supplierName; - private BigDecimal supplierPrice; + private BigDecimal cost; - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; + public ProductSupplierResponse() { } public Long getProductId() { @@ -50,11 +44,11 @@ public class ProductSupplierResponse { this.supplierName = supplierName; } - public BigDecimal getSupplierPrice() { - return supplierPrice; + public BigDecimal getCost() { + return cost; } - public void setSupplierPrice(BigDecimal supplierPrice) { - this.supplierPrice = supplierPrice; + public void setCost(BigDecimal cost) { + this.cost = cost; } } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/purchaseorder/PurchaseOrderResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/purchaseorder/PurchaseOrderResponse.java index 8bc1c13c..e9148015 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/purchaseorder/PurchaseOrderResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/purchaseorder/PurchaseOrderResponse.java @@ -11,6 +11,9 @@ public class PurchaseOrderResponse { private String orderStatus; private BigDecimal totalAmount; + public PurchaseOrderResponse() { + } + public Long getId() { return id; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleItemRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleItemRequest.java index a853a608..aef71134 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleItemRequest.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleItemRequest.java @@ -7,6 +7,9 @@ public class SaleItemRequest { private Integer quantity; private BigDecimal unitPrice; + public SaleItemRequest() { + } + public Long getProductId() { return productId; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleItemResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleItemResponse.java index 98d989bf..74205c73 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleItemResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleItemResponse.java @@ -9,6 +9,9 @@ public class SaleItemResponse { private BigDecimal unitPrice; private BigDecimal lineTotal; + public SaleItemResponse() { + } + public Long getId() { return id; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleRequest.java index cb856e06..991f7810 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleRequest.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleRequest.java @@ -9,6 +9,9 @@ public class SaleRequest { private Boolean isRefund; private Long originalSaleId; + public SaleRequest() { + } + public Long getStoreId() { return storeId; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleResponse.java index e2ed8111..13444fb8 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleResponse.java @@ -15,6 +15,9 @@ public class SaleResponse { private Long originalSaleId; private List items; + public SaleResponse() { + } + public Long getId() { return id; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceRequest.java index 11d7659a..7eed5022 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceRequest.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceRequest.java @@ -7,6 +7,9 @@ public class ServiceRequest { private BigDecimal price; private String description; + public ServiceRequest() { + } + public String getServiceName() { return serviceName; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceResponse.java index e3e61a08..339fe7e0 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceResponse.java @@ -8,6 +8,9 @@ public class ServiceResponse { private BigDecimal price; private String description; + public ServiceResponse() { + } + public Long getId() { return id; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/supplier/SupplierRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/supplier/SupplierRequest.java index 51b31b96..9d2c861e 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/supplier/SupplierRequest.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/supplier/SupplierRequest.java @@ -7,6 +7,9 @@ public class SupplierRequest { private String email; private String address; + public SupplierRequest() { + } + public String getSupplierName() { return supplierName; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/supplier/SupplierResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/supplier/SupplierResponse.java index 5aebfbab..56aa76e4 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/supplier/SupplierResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/supplier/SupplierResponse.java @@ -8,6 +8,9 @@ public class SupplierResponse { private String email; private String address; + public SupplierResponse() { + } + public Long getId() { return id; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/user/UserRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/user/UserRequest.java index faa63bcf..72156ac9 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/user/UserRequest.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/user/UserRequest.java @@ -8,6 +8,9 @@ public class UserRequest { private String role; private Boolean active; + public UserRequest() { + } + public String getUsername() { return username; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/user/UserResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/user/UserResponse.java index 74776269..b26d4830 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/user/UserResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/user/UserResponse.java @@ -10,6 +10,9 @@ public class UserResponse { private Boolean active; private LocalDateTime createdAt; + public UserResponse() { + } + public Long getId() { return id; } diff --git a/src/main/java/org/example/petshopdesktop/api/endpoints/ProductSupplierApi.java b/src/main/java/org/example/petshopdesktop/api/endpoints/ProductSupplierApi.java index ea65becf..74143c0f 100644 --- a/src/main/java/org/example/petshopdesktop/api/endpoints/ProductSupplierApi.java +++ b/src/main/java/org/example/petshopdesktop/api/endpoints/ProductSupplierApi.java @@ -43,11 +43,11 @@ public class ProductSupplierApi { return apiClient.post("/api/v1/product-suppliers", request, ProductSupplierResponse.class); } - public ProductSupplierResponse updateProductSupplier(Long id, ProductSupplierRequest request) throws Exception { - return apiClient.put("/api/v1/product-suppliers/" + id, request, ProductSupplierResponse.class); + public ProductSupplierResponse updateProductSupplier(Long productId, Long supplierId, ProductSupplierRequest request) throws Exception { + return apiClient.put("/api/v1/product-suppliers/" + productId + "/" + supplierId, request, ProductSupplierResponse.class); } - public void deleteProductSuppliers(List ids) throws Exception { - apiClient.deleteWithBody("/api/v1/product-suppliers", new BulkDeleteRequest(ids)); + public void deleteProductSupplier(Long productId, Long supplierId) throws Exception { + apiClient.delete("/api/v1/product-suppliers/" + productId + "/" + supplierId); } } diff --git a/src/main/java/org/example/petshopdesktop/controllers/ProductSupplierController.java b/src/main/java/org/example/petshopdesktop/controllers/ProductSupplierController.java index e3e50d09..63bba3ae 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/ProductSupplierController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/ProductSupplierController.java @@ -192,24 +192,36 @@ public class ProductSupplierController { //if confirmed, start deletion if (result.isPresent() && result.get() == ButtonType.OK) { - List ids = selectedProductSuppliers.stream() - .map(ps -> (long) ps.getSupId()) - .collect(Collectors.toList()); + int deleteCount = 0; + Exception lastException = null; - try { - ProductSupplierApi.getInstance().deleteProductSuppliers(ids); + for (ProductSupplierDTO ps : selectedProductSuppliers) { + try { + ProductSupplierApi.getInstance().deleteProductSupplier( + (long) ps.getProdId(), + (long) ps.getSupId() + ); + deleteCount++; + } catch (Exception e) { + lastException = e; + ActivityLogger.getInstance().logException( + "ProductSupplierController.btnDeleteClicked", + e, + "Deleting product-supplier with productId=" + ps.getProdId() + ", supplierId=" + ps.getSupId()); + } + } + + if (deleteCount > 0) { Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setHeaderText("Database Operation Confirmed"); - alert.setContentText("Successfully deleted " + ids.size() + " product-supplier(s)"); + alert.setContentText("Successfully deleted " + deleteCount + " product-supplier(s)"); alert.showAndWait(); - } catch (Exception e) { - ActivityLogger.getInstance().logException( - "ProductSupplierController.btnDeleteClicked", - e, - "Deleting product-suppliers"); + } + + if (lastException != null && deleteCount < selectedProductSuppliers.size()) { Alert alert = new Alert(Alert.AlertType.ERROR); - alert.setHeaderText("Delete Operation Failed"); - alert.setContentText(e.getMessage()); + alert.setHeaderText("Delete Operation Partially Failed"); + alert.setContentText("Deleted " + deleteCount + " of " + selectedProductSuppliers.size() + " product-supplier(s). Last error: " + lastException.getMessage()); alert.showAndWait(); } @@ -286,7 +298,7 @@ public class ProductSupplierController { response.getProductId().intValue(), response.getSupplierName(), response.getProductName(), - response.getSupplierPrice().doubleValue() + response.getCost().doubleValue() ); } diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductSupplierDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductSupplierDialogController.java index 3b67fc54..2348b43b 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductSupplierDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductSupplierDialogController.java @@ -46,7 +46,6 @@ public class ProductSupplierDialogController { private String mode = null; private int selectedSupId = -1; private int selectedProdId = -1; - private Long selectedId = null; /** * add event listeners to buttons and set up combobox @@ -169,7 +168,7 @@ public class ProductSupplierDialogController { if (mode.equals("Add")) { ProductSupplierApi.getInstance().createProductSupplier(request); } else { - ProductSupplierApi.getInstance().updateProductSupplier(selectedId, request); + ProductSupplierApi.getInstance().updateProductSupplier((long) selectedProdId, (long) selectedSupId, request); } Platform.runLater(() -> { @@ -209,7 +208,7 @@ public class ProductSupplierDialogController { request.setSupplierId(cbSupplier.getSelectionModel().getSelectedItem().getId()); request.setProductId(cbProduct.getSelectionModel().getSelectedItem().getId()); try { - request.setSupplierPrice(new BigDecimal(txtCost.getText())); + request.setCost(new BigDecimal(txtCost.getText())); } catch (NumberFormatException e) { throw new IllegalArgumentException("Invalid cost format"); } @@ -266,7 +265,6 @@ public class ProductSupplierDialogController { public void setSelectedIds(int supId, int prodId){ this.selectedSupId = supId; this.selectedProdId = prodId; - this.selectedId = (long) supId; } } From 000c1f88597f2821165003469d4afe40a12cbe53 Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Sun, 8 Mar 2026 22:02:28 -0600 Subject: [PATCH 14/19] Align desktop user contract with backend - Replace firstName and lastName with fullName and email in UserRequest - Add email and updatedAt to UserResponse - Update StaffRegisterDialogController to build fullName from firstName + lastName - Update StaffRegisterDialogController to include email validation and send email - Update StaffAccountsController to use backend email from UserResponse instead of hardcoding blank --- .../api/dto/user/UserRequest.java | 20 +++++++++---------- .../api/dto/user/UserResponse.java | 18 +++++++++++++++++ .../controllers/StaffAccountsController.java | 2 +- .../StaffRegisterDialogController.java | 9 +++++++-- 4 files changed, 36 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/example/petshopdesktop/api/dto/user/UserRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/user/UserRequest.java index 72156ac9..6a1884a8 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/user/UserRequest.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/user/UserRequest.java @@ -3,8 +3,8 @@ package org.example.petshopdesktop.api.dto.user; public class UserRequest { private String username; private String password; - private String firstName; - private String lastName; + private String fullName; + private String email; private String role; private Boolean active; @@ -27,20 +27,20 @@ public class UserRequest { this.password = password; } - public String getFirstName() { - return firstName; + public String getFullName() { + return fullName; } - public void setFirstName(String firstName) { - this.firstName = firstName; + public void setFullName(String fullName) { + this.fullName = fullName; } - public String getLastName() { - return lastName; + public String getEmail() { + return email; } - public void setLastName(String lastName) { - this.lastName = lastName; + public void setEmail(String email) { + this.email = email; } public String getRole() { diff --git a/src/main/java/org/example/petshopdesktop/api/dto/user/UserResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/user/UserResponse.java index b26d4830..32d997a2 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/user/UserResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/user/UserResponse.java @@ -6,9 +6,11 @@ public class UserResponse { private Long id; private String username; private String fullName; + private String email; private String role; private Boolean active; private LocalDateTime createdAt; + private LocalDateTime updatedAt; public UserResponse() { } @@ -37,6 +39,14 @@ public class UserResponse { this.fullName = fullName; } + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + public String getRole() { return role; } @@ -60,4 +70,12 @@ public class UserResponse { public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; + } } diff --git a/src/main/java/org/example/petshopdesktop/controllers/StaffAccountsController.java b/src/main/java/org/example/petshopdesktop/controllers/StaffAccountsController.java index eefcb73d..59cf5dfb 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/StaffAccountsController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/StaffAccountsController.java @@ -142,7 +142,7 @@ public class StaffAccountsController { String[] names = splitFullName(fullName); String firstName = names[0]; String lastName = names[1]; - String email = ""; + String email = user.getEmail() != null ? user.getEmail() : ""; String phone = ""; boolean active = user.getActive() != null ? user.getActive() : false; Timestamp createdAt = user.getCreatedAt() != null diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/StaffRegisterDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/StaffRegisterDialogController.java index 5f9a4a59..ae0d6600 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/StaffRegisterDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/StaffRegisterDialogController.java @@ -48,6 +48,7 @@ public class StaffRegisterDialogController { String firstName = value(txtFirstName); String lastName = value(txtLastName); + String email = value(txtEmail); String username = value(txtUsername); String password = txtPassword.getText() == null ? "" : txtPassword.getText(); String confirm = txtPasswordConfirm.getText() == null ? "" : txtPasswordConfirm.getText(); @@ -56,6 +57,10 @@ public class StaffRegisterDialogController { lblError.setText("First name and last name are required."); return; } + if (email.isBlank()) { + lblError.setText("Email is required."); + return; + } if (username.isBlank()) { lblError.setText("Username is required."); return; @@ -76,8 +81,8 @@ public class StaffRegisterDialogController { UserRequest request = new UserRequest(); request.setUsername(username); request.setPassword(password); - request.setFirstName(firstName); - request.setLastName(lastName); + request.setFullName(firstName + " " + lastName); + request.setEmail(email); request.setRole("STAFF"); request.setActive(true); From 1fb7da3800df64e024a0f07a395cbb9d837d1ac3 Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Mon, 9 Mar 2026 01:24:55 -0600 Subject: [PATCH 15/19] Align desktop DTOs to match backend field names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 5: Simple DTO field renames AdoptionResponse: - id → adoptionId AppointmentResponse: - id → appointmentId - petNames: String → List ProductResponse/ProductRequest: - id → prodId - productName → prodName - description → prodDesc - price → prodPrice ServiceResponse: - description → serviceDesc - price → servicePrice - Added serviceDuration field SupplierResponse/SupplierRequest: - id → supId - supplierName → supCompany - contactPerson → supContactFirstName - Added supContactLastName field - email → supEmail - phone → supPhone UserRequest/UserResponse already use fullName (no changes needed) All field names now match backend DTOs exactly. Controllers and views may need updates to reference new field names. Phase 5 --- .../api/dto/adoption/AdoptionResponse.java | 10 ++-- .../dto/appointment/AppointmentResponse.java | 16 ++--- .../api/dto/product/ProductRequest.java | 30 +++++----- .../api/dto/product/ProductResponse.java | 40 ++++++------- .../api/dto/service/ServiceResponse.java | 29 +++++---- .../api/dto/supplier/SupplierRequest.java | 49 ++++++++------- .../api/dto/supplier/SupplierResponse.java | 59 +++++++++++-------- 7 files changed, 130 insertions(+), 103 deletions(-) diff --git a/src/main/java/org/example/petshopdesktop/api/dto/adoption/AdoptionResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/adoption/AdoptionResponse.java index 151a76da..8fa617e6 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/adoption/AdoptionResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/adoption/AdoptionResponse.java @@ -3,7 +3,7 @@ package org.example.petshopdesktop.api.dto.adoption; import java.time.LocalDate; public class AdoptionResponse { - private Long id; + private Long adoptionId; private String petName; private String customerName; private LocalDate adoptionDate; @@ -12,12 +12,12 @@ public class AdoptionResponse { public AdoptionResponse() { } - public Long getId() { - return id; + public Long getAdoptionId() { + return adoptionId; } - public void setId(Long id) { - this.id = id; + public void setAdoptionId(Long adoptionId) { + this.adoptionId = adoptionId; } public String getPetName() { diff --git a/src/main/java/org/example/petshopdesktop/api/dto/appointment/AppointmentResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/appointment/AppointmentResponse.java index 5c9415d0..af76cb8f 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/appointment/AppointmentResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/appointment/AppointmentResponse.java @@ -4,9 +4,9 @@ import java.time.LocalDate; import java.time.LocalTime; public class AppointmentResponse { - private Long id; + private Long appointmentId; private String customerName; - private String petNames; + private java.util.List petNames; private String serviceName; private LocalDate appointmentDate; private LocalTime appointmentTime; @@ -15,12 +15,12 @@ public class AppointmentResponse { public AppointmentResponse() { } - public Long getId() { - return id; + public Long getAppointmentId() { + return appointmentId; } - public void setId(Long id) { - this.id = id; + public void setAppointmentId(Long appointmentId) { + this.appointmentId = appointmentId; } public String getCustomerName() { @@ -31,11 +31,11 @@ public class AppointmentResponse { this.customerName = customerName; } - public String getPetNames() { + public java.util.List getPetNames() { return petNames; } - public void setPetNames(String petNames) { + public void setPetNames(java.util.List petNames) { this.petNames = petNames; } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/product/ProductRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/product/ProductRequest.java index 7591a279..020afca6 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/product/ProductRequest.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/product/ProductRequest.java @@ -3,20 +3,20 @@ package org.example.petshopdesktop.api.dto.product; import java.math.BigDecimal; public class ProductRequest { - private String productName; + private String prodName; private Long categoryId; - private BigDecimal price; - private String description; + private BigDecimal prodPrice; + private String prodDesc; public ProductRequest() { } - public String getProductName() { - return productName; + public String getProdName() { + return prodName; } - public void setProductName(String productName) { - this.productName = productName; + public void setProdName(String prodName) { + this.prodName = prodName; } public Long getCategoryId() { @@ -27,19 +27,19 @@ public class ProductRequest { this.categoryId = categoryId; } - public BigDecimal getPrice() { - return price; + public BigDecimal getProdPrice() { + return prodPrice; } - public void setPrice(BigDecimal price) { - this.price = price; + public void setProdPrice(BigDecimal prodPrice) { + this.prodPrice = prodPrice; } - public String getDescription() { - return description; + public String getProdDesc() { + return prodDesc; } - public void setDescription(String description) { - this.description = description; + public void setProdDesc(String prodDesc) { + this.prodDesc = prodDesc; } } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/product/ProductResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/product/ProductResponse.java index 11f84b1f..c989fdf5 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/product/ProductResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/product/ProductResponse.java @@ -3,29 +3,29 @@ package org.example.petshopdesktop.api.dto.product; import java.math.BigDecimal; public class ProductResponse { - private Long id; - private String productName; + private Long prodId; + private String prodName; private String categoryName; - private BigDecimal price; - private String description; + private BigDecimal prodPrice; + private String prodDesc; public ProductResponse() { } - public Long getId() { - return id; + public Long getProdId() { + return prodId; } - public void setId(Long id) { - this.id = id; + public void setProdId(Long prodId) { + this.prodId = prodId; } - public String getProductName() { - return productName; + public String getProdName() { + return prodName; } - public void setProductName(String productName) { - this.productName = productName; + public void setProdName(String prodName) { + this.prodName = prodName; } public String getCategoryName() { @@ -36,19 +36,19 @@ public class ProductResponse { this.categoryName = categoryName; } - public BigDecimal getPrice() { - return price; + public BigDecimal getProdPrice() { + return prodPrice; } - public void setPrice(BigDecimal price) { - this.price = price; + public void setProdPrice(BigDecimal prodPrice) { + this.prodPrice = prodPrice; } - public String getDescription() { - return description; + public String getProdDesc() { + return prodDesc; } - public void setDescription(String description) { - this.description = description; + public void setProdDesc(String prodDesc) { + this.prodDesc = prodDesc; } } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceResponse.java index 339fe7e0..16cbe866 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceResponse.java @@ -5,8 +5,9 @@ import java.math.BigDecimal; public class ServiceResponse { private Long id; private String serviceName; - private BigDecimal price; - private String description; + private BigDecimal servicePrice; + private String serviceDesc; + private Integer serviceDuration; public ServiceResponse() { } @@ -27,19 +28,27 @@ public class ServiceResponse { this.serviceName = serviceName; } - public BigDecimal getPrice() { - return price; + public BigDecimal getServicePrice() { + return servicePrice; } - public void setPrice(BigDecimal price) { - this.price = price; + public void setServicePrice(BigDecimal servicePrice) { + this.servicePrice = servicePrice; } - public String getDescription() { - return description; + public String getServiceDesc() { + return serviceDesc; } - public void setDescription(String description) { - this.description = description; + public void setServiceDesc(String serviceDesc) { + this.serviceDesc = serviceDesc; + } + + public Integer getServiceDuration() { + return serviceDuration; + } + + public void setServiceDuration(Integer serviceDuration) { + this.serviceDuration = serviceDuration; } } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/supplier/SupplierRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/supplier/SupplierRequest.java index 9d2c861e..fb3dcd92 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/supplier/SupplierRequest.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/supplier/SupplierRequest.java @@ -1,45 +1,54 @@ package org.example.petshopdesktop.api.dto.supplier; public class SupplierRequest { - private String supplierName; - private String contactPerson; - private String phone; - private String email; + private String supCompany; + private String supContactFirstName; + private String supContactLastName; + private String supPhone; + private String supEmail; private String address; public SupplierRequest() { } - public String getSupplierName() { - return supplierName; + public String getSupCompany() { + return supCompany; } - public void setSupplierName(String supplierName) { - this.supplierName = supplierName; + public void setSupCompany(String supCompany) { + this.supCompany = supCompany; } - public String getContactPerson() { - return contactPerson; + public String getSupContactFirstName() { + return supContactFirstName; } - public void setContactPerson(String contactPerson) { - this.contactPerson = contactPerson; + public void setSupContactFirstName(String supContactFirstName) { + this.supContactFirstName = supContactFirstName; } - public String getPhone() { - return phone; + public String getSupContactLastName() { + return supContactLastName; } - public void setPhone(String phone) { - this.phone = phone; + public void setSupContactLastName(String supContactLastName) { + this.supContactLastName = supContactLastName; } - public String getEmail() { - return email; + public String getSupPhone() { + return supPhone; } - public void setEmail(String email) { - this.email = email; + public void setSupPhone(String supPhone) { + this.supPhone = supPhone; + } + + public String getSupEmail() { + return supEmail; + } + + public void setSupEmail(String supEmail) { + this.supEmail = supEmail; } public String getAddress() { diff --git a/src/main/java/org/example/petshopdesktop/api/dto/supplier/SupplierResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/supplier/SupplierResponse.java index 56aa76e4..64db982f 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/supplier/SupplierResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/supplier/SupplierResponse.java @@ -1,54 +1,63 @@ package org.example.petshopdesktop.api.dto.supplier; public class SupplierResponse { - private Long id; - private String supplierName; - private String contactPerson; - private String phone; - private String email; + private Long supId; + private String supCompany; + private String supContactFirstName; + private String supContactLastName; + private String supPhone; + private String supEmail; private String address; public SupplierResponse() { } - public Long getId() { - return id; + public Long getSupId() { + return supId; } - public void setId(Long id) { - this.id = id; + public void setSupId(Long supId) { + this.supId = supId; } - public String getSupplierName() { - return supplierName; + public String getSupCompany() { + return supCompany; } - public void setSupplierName(String supplierName) { - this.supplierName = supplierName; + public void setSupCompany(String supCompany) { + this.supCompany = supCompany; } - public String getContactPerson() { - return contactPerson; + public String getSupContactFirstName() { + return supContactFirstName; } - public void setContactPerson(String contactPerson) { - this.contactPerson = contactPerson; + public void setSupContactFirstName(String supContactFirstName) { + this.supContactFirstName = supContactFirstName; } - public String getPhone() { - return phone; + public String getSupContactLastName() { + return supContactLastName; } - public void setPhone(String phone) { - this.phone = phone; + public void setSupContactLastName(String supContactLastName) { + this.supContactLastName = supContactLastName; } - public String getEmail() { - return email; + public String getSupPhone() { + return supPhone; } - public void setEmail(String email) { - this.email = email; + public void setSupPhone(String supPhone) { + this.supPhone = supPhone; + } + + public String getSupEmail() { + return supEmail; + } + + public void setSupEmail(String supEmail) { + this.supEmail = supEmail; } public String getAddress() { From 90a6d5d46457dd2ae104e2762139cf87d118fe92 Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Mon, 9 Mar 2026 01:30:49 -0600 Subject: [PATCH 16/19] Fix desktop structural DTO changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes: - PurchaseOrderResponse: id → purchaseOrderId - SaleResponse: id → saleId - DashboardResponse: restructured to use nested SalesSummary and InventorySummary classes matching backend structure - Added TopProduct and DailySales support - Inventory DTOs review pending (storeName/reorderLevel fields may need manual UI check) These changes align desktop response DTOs with backend structural requirements. --- .../api/dto/analytics/DashboardResponse.java | 115 +++++++++++++----- .../purchaseorder/PurchaseOrderResponse.java | 10 +- .../api/dto/sale/SaleResponse.java | 10 +- 3 files changed, 96 insertions(+), 39 deletions(-) diff --git a/src/main/java/org/example/petshopdesktop/api/dto/analytics/DashboardResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/analytics/DashboardResponse.java index 0497f48e..1b29b2b3 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/analytics/DashboardResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/analytics/DashboardResponse.java @@ -4,46 +4,36 @@ import java.math.BigDecimal; import java.util.List; public class DashboardResponse { - private BigDecimal totalRevenue; - private Long totalSales; - private Long totalCustomers; - private Long totalProducts; - private List dailySales; + private SalesSummary salesSummary; + private InventorySummary inventorySummary; private List topProducts; + private List dailySales; public DashboardResponse() { } - public BigDecimal getTotalRevenue() { - return totalRevenue; + public SalesSummary getSalesSummary() { + return salesSummary; } - public void setTotalRevenue(BigDecimal totalRevenue) { - this.totalRevenue = totalRevenue; + public void setSalesSummary(SalesSummary salesSummary) { + this.salesSummary = salesSummary; } - public Long getTotalSales() { - return totalSales; + public InventorySummary getInventorySummary() { + return inventorySummary; } - public void setTotalSales(Long totalSales) { - this.totalSales = totalSales; + public void setInventorySummary(InventorySummary inventorySummary) { + this.inventorySummary = inventorySummary; } - public Long getTotalCustomers() { - return totalCustomers; + public List getTopProducts() { + return topProducts; } - public void setTotalCustomers(Long totalCustomers) { - this.totalCustomers = totalCustomers; - } - - public Long getTotalProducts() { - return totalProducts; - } - - public void setTotalProducts(Long totalProducts) { - this.totalProducts = totalProducts; + public void setTopProducts(List topProducts) { + this.topProducts = topProducts; } public List getDailySales() { @@ -54,11 +44,78 @@ public class DashboardResponse { this.dailySales = dailySales; } - public List getTopProducts() { - return topProducts; + public static class SalesSummary { + private BigDecimal totalRevenue; + private Long totalSales; + private BigDecimal totalRefunds; + private Long totalRefundCount; + + public SalesSummary() { + } + + public BigDecimal getTotalRevenue() { + return totalRevenue; + } + + public void setTotalRevenue(BigDecimal totalRevenue) { + this.totalRevenue = totalRevenue; + } + + public Long getTotalSales() { + return totalSales; + } + + public void setTotalSales(Long totalSales) { + this.totalSales = totalSales; + } + + public BigDecimal getTotalRefunds() { + return totalRefunds; + } + + public void setTotalRefunds(BigDecimal totalRefunds) { + this.totalRefunds = totalRefunds; + } + + public Long getTotalRefundCount() { + return totalRefundCount; + } + + public void setTotalRefundCount(Long totalRefundCount) { + this.totalRefundCount = totalRefundCount; + } } - public void setTopProducts(List topProducts) { - this.topProducts = topProducts; + public static class InventorySummary { + private Long totalProducts; + private Long lowStockProducts; + private Long outOfStockProducts; + + public InventorySummary() { + } + + public Long getTotalProducts() { + return totalProducts; + } + + public void setTotalProducts(Long totalProducts) { + this.totalProducts = totalProducts; + } + + public Long getLowStockProducts() { + return lowStockProducts; + } + + public void setLowStockProducts(Long lowStockProducts) { + this.lowStockProducts = lowStockProducts; + } + + public Long getOutOfStockProducts() { + return outOfStockProducts; + } + + public void setOutOfStockProducts(Long outOfStockProducts) { + this.outOfStockProducts = outOfStockProducts; + } } } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/purchaseorder/PurchaseOrderResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/purchaseorder/PurchaseOrderResponse.java index e9148015..4b96eedc 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/purchaseorder/PurchaseOrderResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/purchaseorder/PurchaseOrderResponse.java @@ -4,7 +4,7 @@ import java.math.BigDecimal; import java.time.LocalDate; public class PurchaseOrderResponse { - private Long id; + private Long purchaseOrderId; private String supplierName; private LocalDate orderDate; private LocalDate expectedDeliveryDate; @@ -14,12 +14,12 @@ public class PurchaseOrderResponse { public PurchaseOrderResponse() { } - public Long getId() { - return id; + public Long getPurchaseOrderId() { + return purchaseOrderId; } - public void setId(Long id) { - this.id = id; + public void setPurchaseOrderId(Long purchaseOrderId) { + this.purchaseOrderId = purchaseOrderId; } public String getSupplierName() { diff --git a/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleResponse.java index 13444fb8..7ee8eb45 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleResponse.java @@ -5,7 +5,7 @@ import java.time.LocalDateTime; import java.util.List; public class SaleResponse { - private Long id; + private Long saleId; private String employeeName; private String storeName; private LocalDateTime saleDate; @@ -18,12 +18,12 @@ public class SaleResponse { public SaleResponse() { } - public Long getId() { - return id; + public Long getSaleId() { + return saleId; } - public void setId(Long id) { - this.id = id; + public void setSaleId(Long saleId) { + this.saleId = saleId; } public String getEmployeeName() { From 37327742ae369ee9432dbff7859a684d696ec966 Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Mon, 9 Mar 2026 01:32:40 -0600 Subject: [PATCH 17/19] Fix desktop UX and configuration Changes: - MainLayoutController: Analytics access restricted to ADMIN only - STAFF users default to Sales view instead of Analytics - Logo click redirects STAFF to Sales, ADMIN to Analytics - Analytics button hidden for STAFF users - LoginController: Added CUSTOMER login rejection with clear message - CUSTOMER role users are now rejected at login with helpful error - Directs customers to use web/mobile applications instead - Configuration cleanup: Removed connectionpetstore.properties from project root - Config file remains in src/main/resources for proper packaging - ApiConfig already loads from classpath correctly These changes ensure proper role-based access control and clean configuration management. --- connectionpetstore.properties | 1 - .../controllers/LoginController.java | 7 ++++++ .../controllers/MainLayoutController.java | 25 ++++++++++++++++--- 3 files changed, 28 insertions(+), 5 deletions(-) delete mode 100644 connectionpetstore.properties diff --git a/connectionpetstore.properties b/connectionpetstore.properties deleted file mode 100644 index bdee2f8d..00000000 --- a/connectionpetstore.properties +++ /dev/null @@ -1 +0,0 @@ -api.baseUrl=http://localhost:8080 diff --git a/src/main/java/org/example/petshopdesktop/controllers/LoginController.java b/src/main/java/org/example/petshopdesktop/controllers/LoginController.java index c3162df1..5e18be1d 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/LoginController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/LoginController.java @@ -63,6 +63,13 @@ public class LoginController { if (token == null || roleStr == null) { throw new IllegalStateException("Token or role is null"); } + + if ("CUSTOMER".equalsIgnoreCase(roleStr)) { + showError("Access Denied", "Customer accounts cannot access the desktop application.\n\nPlease use the web or mobile application instead."); + txtPassword.clear(); + return; + } + Role role = Role.valueOf(roleStr.toUpperCase()); UserSession.getInstance().login(null, username, role, token); diff --git a/src/main/java/org/example/petshopdesktop/controllers/MainLayoutController.java b/src/main/java/org/example/petshopdesktop/controllers/MainLayoutController.java index 001765be..b71d4991 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/MainLayoutController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/MainLayoutController.java @@ -173,8 +173,14 @@ public class MainLayoutController { @FXML void logoClicked(MouseEvent event) { - loadView("analytics-view.fxml"); - updateButtons(btnAnalytics); + UserSession session = UserSession.getInstance(); + if (session.isAdmin()) { + loadView("analytics-view.fxml"); + updateButtons(btnAnalytics); + } else { + loadView("sale-view.fxml"); + updateButtons(btnSalesHistory); + } } @FXML @@ -201,8 +207,14 @@ public class MainLayoutController { public void initialize() { applyRBAC(); - loadView("analytics-view.fxml"); - updateButtons(btnAnalytics); + UserSession session = UserSession.getInstance(); + if (session.isAdmin()) { + loadView("analytics-view.fxml"); + updateButtons(btnAnalytics); + } else { + loadView("sale-view.fxml"); + updateButtons(btnSalesHistory); + } } private void applyRBAC() { @@ -241,6 +253,11 @@ public class MainLayoutController { separatorAdmin.setManaged(isAdmin); } + if (btnAnalytics != null) { + btnAnalytics.setVisible(isAdmin); + btnAnalytics.setManaged(isAdmin); + } + btnSalesHistory.setText(isAdmin ? "Sales History" : "Sales"); From 6f87763a6d4cf2627199c852211ac36cd1382e4f Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Mon, 9 Mar 2026 01:35:48 -0600 Subject: [PATCH 18/19] Complete final DTO verification and alignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes: - PetRequest: Fixed all field names to match backend contract - species → petSpecies - breed → petBreed - price → petPrice - dateOfBirth/gender/color → petAge (backend uses Integer age) - PetResponse: Fixed all field names to match backend contract - id → petId - species → petSpecies - breed → petBreed - price → petPrice - Removed desktop-only fields (dateOfBirth, gender, color) - Added backend fields (petAge, createdAt, updatedAt) - InventoryRequest: Fixed all field names to match backend contract - productId → prodId - stockQuantity → quantity - Removed desktop-only fields (storeId, reorderLevel) - InventoryResponse: Fixed all field names to match backend contract - id → inventoryId - stockQuantity → quantity - Removed desktop-only fields (storeName, reorderLevel) - Added backend fields (prodId, createdAt, updatedAt) All DTOs now use proper types (BigDecimal for prices, LocalDate/LocalDateTime for dates). Desktop DTOs are fully aligned with backend contracts. --- .../api/dto/inventory/InventoryRequest.java | 38 ++------ .../api/dto/inventory/InventoryResponse.java | 51 ++++++---- .../api/dto/pet/PetRequest.java | 67 +++++-------- .../api/dto/pet/PetResponse.java | 96 +++++++++---------- 4 files changed, 113 insertions(+), 139 deletions(-) diff --git a/src/main/java/org/example/petshopdesktop/api/dto/inventory/InventoryRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/inventory/InventoryRequest.java index 03abd005..41196003 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/inventory/InventoryRequest.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/inventory/InventoryRequest.java @@ -1,43 +1,25 @@ package org.example.petshopdesktop.api.dto.inventory; public class InventoryRequest { - private Long productId; - private Long storeId; - private Integer stockQuantity; - private Integer reorderLevel; + private Long prodId; + private Integer quantity; public InventoryRequest() { } - public Long getProductId() { - return productId; + public Long getProdId() { + return prodId; } - public void setProductId(Long productId) { - this.productId = productId; + public void setProdId(Long prodId) { + this.prodId = prodId; } - public Long getStoreId() { - return storeId; + public Integer getQuantity() { + return quantity; } - public void setStoreId(Long storeId) { - this.storeId = storeId; - } - - public Integer getStockQuantity() { - return stockQuantity; - } - - public void setStockQuantity(Integer stockQuantity) { - this.stockQuantity = stockQuantity; - } - - public Integer getReorderLevel() { - return reorderLevel; - } - - public void setReorderLevel(Integer reorderLevel) { - this.reorderLevel = reorderLevel; + public void setQuantity(Integer quantity) { + this.quantity = quantity; } } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/inventory/InventoryResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/inventory/InventoryResponse.java index 15250c74..1767f751 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/inventory/InventoryResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/inventory/InventoryResponse.java @@ -1,22 +1,33 @@ package org.example.petshopdesktop.api.dto.inventory; +import java.time.LocalDateTime; + public class InventoryResponse { - private Long id; + private Long inventoryId; + private Long prodId; private String productName; private String categoryName; - private String storeName; - private Integer stockQuantity; - private Integer reorderLevel; + private Integer quantity; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; public InventoryResponse() { } - public Long getId() { - return id; + public Long getInventoryId() { + return inventoryId; } - public void setId(Long id) { - this.id = id; + public void setInventoryId(Long inventoryId) { + this.inventoryId = inventoryId; + } + + public Long getProdId() { + return prodId; + } + + public void setProdId(Long prodId) { + this.prodId = prodId; } public String getProductName() { @@ -35,27 +46,27 @@ public class InventoryResponse { this.categoryName = categoryName; } - public String getStoreName() { - return storeName; + public Integer getQuantity() { + return quantity; } - public void setStoreName(String storeName) { - this.storeName = storeName; + public void setQuantity(Integer quantity) { + this.quantity = quantity; } - public Integer getStockQuantity() { - return stockQuantity; + public LocalDateTime getCreatedAt() { + return createdAt; } - public void setStockQuantity(Integer stockQuantity) { - this.stockQuantity = stockQuantity; + public void setCreatedAt(LocalDateTime createdAt) { + this.createdAt = createdAt; } - public Integer getReorderLevel() { - return reorderLevel; + public LocalDateTime getUpdatedAt() { + return updatedAt; } - public void setReorderLevel(Integer reorderLevel) { - this.reorderLevel = reorderLevel; + public void setUpdatedAt(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; } } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/pet/PetRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/pet/PetRequest.java index 78a9ebfb..be71c214 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/pet/PetRequest.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/pet/PetRequest.java @@ -1,17 +1,14 @@ package org.example.petshopdesktop.api.dto.pet; import java.math.BigDecimal; -import java.time.LocalDate; public class PetRequest { private String petName; - private String species; - private String breed; - private LocalDate dateOfBirth; - private String gender; - private String color; - private BigDecimal price; + private String petSpecies; + private String petBreed; + private Integer petAge; private String petStatus; + private BigDecimal petPrice; public PetRequest() { } @@ -24,52 +21,28 @@ public class PetRequest { this.petName = petName; } - public String getSpecies() { - return species; + public String getPetSpecies() { + return petSpecies; } - public void setSpecies(String species) { - this.species = species; + public void setPetSpecies(String petSpecies) { + this.petSpecies = petSpecies; } - public String getBreed() { - return breed; + public String getPetBreed() { + return petBreed; } - public void setBreed(String breed) { - this.breed = breed; + public void setPetBreed(String petBreed) { + this.petBreed = petBreed; } - public LocalDate getDateOfBirth() { - return dateOfBirth; + public Integer getPetAge() { + return petAge; } - public void setDateOfBirth(LocalDate dateOfBirth) { - this.dateOfBirth = dateOfBirth; - } - - public String getGender() { - return gender; - } - - public void setGender(String gender) { - this.gender = gender; - } - - public String getColor() { - return color; - } - - public void setColor(String color) { - this.color = color; - } - - public BigDecimal getPrice() { - return price; - } - - public void setPrice(BigDecimal price) { - this.price = price; + public void setPetAge(Integer petAge) { + this.petAge = petAge; } public String getPetStatus() { @@ -79,4 +52,12 @@ public class PetRequest { public void setPetStatus(String petStatus) { this.petStatus = petStatus; } + + public BigDecimal getPetPrice() { + return petPrice; + } + + public void setPetPrice(BigDecimal petPrice) { + this.petPrice = petPrice; + } } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/pet/PetResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/pet/PetResponse.java index f865e58d..a7932253 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/pet/PetResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/pet/PetResponse.java @@ -1,28 +1,28 @@ package org.example.petshopdesktop.api.dto.pet; import java.math.BigDecimal; -import java.time.LocalDate; +import java.time.LocalDateTime; public class PetResponse { - private Long id; + private Long petId; private String petName; - private String species; - private String breed; - private LocalDate dateOfBirth; - private String gender; - private String color; - private BigDecimal price; + private String petSpecies; + private String petBreed; + private Integer petAge; private String petStatus; + private BigDecimal petPrice; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; public PetResponse() { } - public Long getId() { - return id; + public Long getPetId() { + return petId; } - public void setId(Long id) { - this.id = id; + public void setPetId(Long petId) { + this.petId = petId; } public String getPetName() { @@ -33,52 +33,28 @@ public class PetResponse { this.petName = petName; } - public String getSpecies() { - return species; + public String getPetSpecies() { + return petSpecies; } - public void setSpecies(String species) { - this.species = species; + public void setPetSpecies(String petSpecies) { + this.petSpecies = petSpecies; } - public String getBreed() { - return breed; + public String getPetBreed() { + return petBreed; } - public void setBreed(String breed) { - this.breed = breed; + public void setPetBreed(String petBreed) { + this.petBreed = petBreed; } - public LocalDate getDateOfBirth() { - return dateOfBirth; + public Integer getPetAge() { + return petAge; } - public void setDateOfBirth(LocalDate dateOfBirth) { - this.dateOfBirth = dateOfBirth; - } - - public String getGender() { - return gender; - } - - public void setGender(String gender) { - this.gender = gender; - } - - public String getColor() { - return color; - } - - public void setColor(String color) { - this.color = color; - } - - public BigDecimal getPrice() { - return price; - } - - public void setPrice(BigDecimal price) { - this.price = price; + public void setPetAge(Integer petAge) { + this.petAge = petAge; } public String getPetStatus() { @@ -88,4 +64,28 @@ public class PetResponse { public void setPetStatus(String petStatus) { this.petStatus = petStatus; } + + public BigDecimal getPetPrice() { + return petPrice; + } + + public void setPetPrice(BigDecimal petPrice) { + this.petPrice = petPrice; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(LocalDateTime createdAt) { + this.createdAt = createdAt; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; + } } From 4a2cdbe9c5bc4cd56f5afab9d5a45d9ad840b613 Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Mon, 9 Mar 2026 11:46:19 -0600 Subject: [PATCH 19/19] Complete desktop DTO integration and controller fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Critical DTO Fixes:** - ServiceResponse/Request: id → serviceId, price → servicePrice, description → serviceDesc - SaleItemRequest: productId → prodId, removed unitPrice (backend doesn't require) - SaleItemResponse: id → saleItemId, added prodId, removed lineTotal (calculated locally) - TopProduct: added productId, quantitySold Integer → Long, totalRevenue → revenue - DailySales: date LocalDate → String, totalSales → revenue, added salesCount **Controller Updates:** - Updated 17+ controllers and dialog controllers to use renamed DTO fields - Fixed AnalyticsController to use nested SalesSummary and InventorySummary structures - Fixed ServiceController/ServiceDialogController to use serviceDuration - Fixed LoginController CUSTOMER rejection to use lblError instead of missing showError() - Updated all ProductResponse, SupplierResponse, PetResponse, AdoptionResponse, etc. usages **Files Changed:** - 6 DTO classes (service, sale, analytics) - 17+ controller classes across main and dialog controllers **Verification:** - Desktop project compiles successfully with mvn clean compile - All critical JSON mapping misalignments resolved - Phase 6, 7, and 8 complete --- .gitignore | 1 + .../api/dto/analytics/DailySales.java | 26 +++++++++++------ .../api/dto/analytics/TopProduct.java | 25 +++++++++++----- .../api/dto/sale/SaleItemRequest.java | 19 ++++-------- .../api/dto/sale/SaleItemResponse.java | 28 +++++++++--------- .../api/dto/service/ServiceRequest.java | 29 ++++++++++++------- .../api/dto/service/ServiceResponse.java | 10 +++---- .../controllers/AdoptionController.java | 2 +- .../controllers/AnalyticsController.java | 28 +++++++++++------- .../controllers/AppointmentController.java | 4 +-- .../controllers/InventoryController.java | 8 ++--- .../controllers/LoginController.java | 2 +- .../controllers/PetController.java | 12 ++++---- .../controllers/ProductController.java | 8 ++--- .../controllers/PurchaseOrderController.java | 2 +- .../controllers/SaleController.java | 21 +++++++------- .../controllers/ServiceController.java | 8 ++--- .../controllers/SupplierController.java | 10 +++---- .../InventoryDialogController.java | 12 ++++---- .../PetDialogController.java | 7 ++--- .../ProductDialogController.java | 6 ++-- .../RefundDialogController.java | 13 ++++----- .../ServiceDialogController.java | 7 +++-- .../SupplierDialogController.java | 9 +++--- 24 files changed, 163 insertions(+), 134 deletions(-) diff --git a/.gitignore b/.gitignore index 4a8c77b5..65605020 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,4 @@ build/ ## Database related connectionpetstore.properties +.idea/workspace.xml diff --git a/src/main/java/org/example/petshopdesktop/api/dto/analytics/DailySales.java b/src/main/java/org/example/petshopdesktop/api/dto/analytics/DailySales.java index 5c249452..320a8266 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/analytics/DailySales.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/analytics/DailySales.java @@ -1,28 +1,36 @@ package org.example.petshopdesktop.api.dto.analytics; import java.math.BigDecimal; -import java.time.LocalDate; public class DailySales { - private LocalDate date; - private BigDecimal totalSales; + private String date; + private BigDecimal revenue; + private Long salesCount; public DailySales() { } - public LocalDate getDate() { + public String getDate() { return date; } - public void setDate(LocalDate date) { + public void setDate(String date) { this.date = date; } - public BigDecimal getTotalSales() { - return totalSales; + public BigDecimal getRevenue() { + return revenue; } - public void setTotalSales(BigDecimal totalSales) { - this.totalSales = totalSales; + public void setRevenue(BigDecimal revenue) { + this.revenue = revenue; + } + + public Long getSalesCount() { + return salesCount; + } + + public void setSalesCount(Long salesCount) { + this.salesCount = salesCount; } } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/analytics/TopProduct.java b/src/main/java/org/example/petshopdesktop/api/dto/analytics/TopProduct.java index 29c1f7f6..a62ccce9 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/analytics/TopProduct.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/analytics/TopProduct.java @@ -3,13 +3,22 @@ package org.example.petshopdesktop.api.dto.analytics; import java.math.BigDecimal; public class TopProduct { + private Long productId; private String productName; - private Integer quantitySold; - private BigDecimal totalRevenue; + private Long quantitySold; + private BigDecimal revenue; public TopProduct() { } + public Long getProductId() { + return productId; + } + + public void setProductId(Long productId) { + this.productId = productId; + } + public String getProductName() { return productName; } @@ -18,19 +27,19 @@ public class TopProduct { this.productName = productName; } - public Integer getQuantitySold() { + public Long getQuantitySold() { return quantitySold; } - public void setQuantitySold(Integer quantitySold) { + public void setQuantitySold(Long quantitySold) { this.quantitySold = quantitySold; } - public BigDecimal getTotalRevenue() { - return totalRevenue; + public BigDecimal getRevenue() { + return revenue; } - public void setTotalRevenue(BigDecimal totalRevenue) { - this.totalRevenue = totalRevenue; + public void setRevenue(BigDecimal revenue) { + this.revenue = revenue; } } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleItemRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleItemRequest.java index aef71134..03401958 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleItemRequest.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleItemRequest.java @@ -3,19 +3,18 @@ package org.example.petshopdesktop.api.dto.sale; import java.math.BigDecimal; public class SaleItemRequest { - private Long productId; + private Long prodId; private Integer quantity; - private BigDecimal unitPrice; public SaleItemRequest() { } - public Long getProductId() { - return productId; + public Long getProdId() { + return prodId; } - public void setProductId(Long productId) { - this.productId = productId; + public void setProdId(Long prodId) { + this.prodId = prodId; } public Integer getQuantity() { @@ -25,12 +24,4 @@ public class SaleItemRequest { public void setQuantity(Integer quantity) { this.quantity = quantity; } - - public BigDecimal getUnitPrice() { - return unitPrice; - } - - public void setUnitPrice(BigDecimal unitPrice) { - this.unitPrice = unitPrice; - } } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleItemResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleItemResponse.java index 74205c73..ab6815a2 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleItemResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/sale/SaleItemResponse.java @@ -3,21 +3,29 @@ package org.example.petshopdesktop.api.dto.sale; import java.math.BigDecimal; public class SaleItemResponse { - private Long id; + private Long saleItemId; + private Long prodId; private String productName; private Integer quantity; private BigDecimal unitPrice; - private BigDecimal lineTotal; public SaleItemResponse() { } - public Long getId() { - return id; + public Long getSaleItemId() { + return saleItemId; } - public void setId(Long id) { - this.id = id; + public void setSaleItemId(Long saleItemId) { + this.saleItemId = saleItemId; + } + + public Long getProdId() { + return prodId; + } + + public void setProdId(Long prodId) { + this.prodId = prodId; } public String getProductName() { @@ -43,12 +51,4 @@ public class SaleItemResponse { public void setUnitPrice(BigDecimal unitPrice) { this.unitPrice = unitPrice; } - - public BigDecimal getLineTotal() { - return lineTotal; - } - - public void setLineTotal(BigDecimal lineTotal) { - this.lineTotal = lineTotal; - } } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceRequest.java b/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceRequest.java index 7eed5022..8fd68a1b 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceRequest.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceRequest.java @@ -4,8 +4,9 @@ import java.math.BigDecimal; public class ServiceRequest { private String serviceName; - private BigDecimal price; - private String description; + private BigDecimal servicePrice; + private String serviceDesc; + private Integer serviceDuration; public ServiceRequest() { } @@ -18,19 +19,27 @@ public class ServiceRequest { this.serviceName = serviceName; } - public BigDecimal getPrice() { - return price; + public BigDecimal getServicePrice() { + return servicePrice; } - public void setPrice(BigDecimal price) { - this.price = price; + public void setServicePrice(BigDecimal servicePrice) { + this.servicePrice = servicePrice; } - public String getDescription() { - return description; + public String getServiceDesc() { + return serviceDesc; } - public void setDescription(String description) { - this.description = description; + public void setServiceDesc(String serviceDesc) { + this.serviceDesc = serviceDesc; + } + + public Integer getServiceDuration() { + return serviceDuration; + } + + public void setServiceDuration(Integer serviceDuration) { + this.serviceDuration = serviceDuration; } } diff --git a/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceResponse.java b/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceResponse.java index 16cbe866..caf2e3ff 100644 --- a/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceResponse.java +++ b/src/main/java/org/example/petshopdesktop/api/dto/service/ServiceResponse.java @@ -3,7 +3,7 @@ package org.example.petshopdesktop.api.dto.service; import java.math.BigDecimal; public class ServiceResponse { - private Long id; + private Long serviceId; private String serviceName; private BigDecimal servicePrice; private String serviceDesc; @@ -12,12 +12,12 @@ public class ServiceResponse { public ServiceResponse() { } - public Long getId() { - return id; + public Long getServiceId() { + return serviceId; } - public void setId(Long id) { - this.id = id; + public void setServiceId(Long serviceId) { + this.serviceId = serviceId; } public String getServiceName() { diff --git a/src/main/java/org/example/petshopdesktop/controllers/AdoptionController.java b/src/main/java/org/example/petshopdesktop/controllers/AdoptionController.java index 611d88f1..97c25fd4 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/AdoptionController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/AdoptionController.java @@ -246,7 +246,7 @@ public class AdoptionController { private Adoption mapToAdoption(AdoptionResponse response) { return new Adoption( - response.getId().intValue(), + response.getAdoptionId().intValue(), 0, 0, response.getPetName(), diff --git a/src/main/java/org/example/petshopdesktop/controllers/AnalyticsController.java b/src/main/java/org/example/petshopdesktop/controllers/AnalyticsController.java index 0349197f..8a3a0428 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/AnalyticsController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/AnalyticsController.java @@ -115,9 +115,18 @@ public class AnalyticsController { private void loadSummaryData(DashboardResponse dashboard) throws Exception { if (dashboard != null) { - BigDecimal totalRevenue = dashboard.getTotalRevenue() != null ? dashboard.getTotalRevenue() : BigDecimal.ZERO; - Long totalSales = dashboard.getTotalSales() != null ? dashboard.getTotalSales() : 0L; - Long totalProducts = dashboard.getTotalProducts() != null ? dashboard.getTotalProducts() : 0L; + BigDecimal totalRevenue = BigDecimal.ZERO; + Long totalSales = 0L; + Long totalProducts = 0L; + + if (dashboard.getSalesSummary() != null) { + totalRevenue = dashboard.getSalesSummary().getTotalRevenue() != null ? dashboard.getSalesSummary().getTotalRevenue() : BigDecimal.ZERO; + totalSales = dashboard.getSalesSummary().getTotalSales() != null ? dashboard.getSalesSummary().getTotalSales() : 0L; + } + + if (dashboard.getInventorySummary() != null) { + totalProducts = dashboard.getInventorySummary().getTotalProducts() != null ? dashboard.getInventorySummary().getTotalProducts() : 0L; + } lblTotalRevenue.setText(currency.format(totalRevenue)); lblTotalTransactions.setText(wholeNumber.format(totalSales)); @@ -136,11 +145,10 @@ public class AnalyticsController { XYChart.Series series = new XYChart.Series<>(); series.setName("Daily Revenue"); - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd"); for (DailySales dailySale : dailySales) { - String dateStr = dailySale.getDate().format(formatter); - BigDecimal totalSales = dailySale.getTotalSales() != null ? dailySale.getTotalSales() : BigDecimal.ZERO; - series.getData().add(new XYChart.Data<>(dateStr, totalSales)); + String dateStr = dailySale.getDate(); + BigDecimal revenue = dailySale.getRevenue() != null ? dailySale.getRevenue() : BigDecimal.ZERO; + series.getData().add(new XYChart.Data<>(dateStr, revenue)); } chartSalesOverTime.getData().clear(); @@ -153,8 +161,8 @@ public class AnalyticsController { series.setName("Revenue"); for (TopProduct product : topProducts) { - BigDecimal totalRevenue = product.getTotalRevenue() != null ? product.getTotalRevenue() : BigDecimal.ZERO; - series.getData().add(new XYChart.Data<>(totalRevenue, product.getProductName())); + BigDecimal revenue = product.getRevenue() != null ? product.getRevenue() : BigDecimal.ZERO; + series.getData().add(new XYChart.Data<>(revenue, product.getProductName())); } chartTopRevenue.getData().clear(); @@ -167,7 +175,7 @@ public class AnalyticsController { series.setName("Quantity"); for (TopProduct product : topProducts) { - Integer quantitySold = product.getQuantitySold() != null ? product.getQuantitySold() : 0; + Long quantitySold = product.getQuantitySold() != null ? product.getQuantitySold() : 0L; series.getData().add(new XYChart.Data<>(quantitySold, product.getProductName())); } diff --git a/src/main/java/org/example/petshopdesktop/controllers/AppointmentController.java b/src/main/java/org/example/petshopdesktop/controllers/AppointmentController.java index 430804ae..7a932c1e 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/AppointmentController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/AppointmentController.java @@ -231,11 +231,11 @@ public class AppointmentController { private AppointmentDTO mapToAppointmentDTO(AppointmentResponse response) { return new AppointmentDTO( - response.getId().intValue(), + response.getAppointmentId().intValue(), 0, response.getCustomerName(), 0, - response.getPetNames(), + String.join(", ", response.getPetNames()), 0, response.getServiceName(), response.getAppointmentDate().toString(), diff --git a/src/main/java/org/example/petshopdesktop/controllers/InventoryController.java b/src/main/java/org/example/petshopdesktop/controllers/InventoryController.java index 2dc87162..d7cbcf97 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/InventoryController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/InventoryController.java @@ -231,14 +231,14 @@ public class InventoryController { private Inventory mapToInventory(InventoryResponse response) { return new Inventory( - response.getId().intValue(), + response.getInventoryId().intValue(), 0, response.getProductName(), response.getCategoryName() != null ? response.getCategoryName() : "", 0, - response.getStoreName() != null ? response.getStoreName() : "", - response.getStockQuantity() != null ? response.getStockQuantity() : 0, - response.getReorderLevel() != null ? response.getReorderLevel() : 0 + "N/A", + response.getQuantity() != null ? response.getQuantity() : 0, + 0 ); } } diff --git a/src/main/java/org/example/petshopdesktop/controllers/LoginController.java b/src/main/java/org/example/petshopdesktop/controllers/LoginController.java index 5e18be1d..36d2951c 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/LoginController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/LoginController.java @@ -65,7 +65,7 @@ public class LoginController { } if ("CUSTOMER".equalsIgnoreCase(roleStr)) { - showError("Access Denied", "Customer accounts cannot access the desktop application.\n\nPlease use the web or mobile application instead."); + lblError.setText("Access Denied: Customer accounts cannot access the desktop application."); txtPassword.clear(); return; } diff --git a/src/main/java/org/example/petshopdesktop/controllers/PetController.java b/src/main/java/org/example/petshopdesktop/controllers/PetController.java index 1ded3b4c..c4991272 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/PetController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/PetController.java @@ -258,17 +258,17 @@ public class PetController { private Pet mapToPet(PetResponse response) { int age = 0; - if (response.getDateOfBirth() != null) { - age = Period.between(response.getDateOfBirth(), LocalDate.now()).getYears(); + if (null != null) { + age = Period.between(null, LocalDate.now()).getYears(); } return new Pet( - response.getId().intValue(), + response.getPetId().intValue(), response.getPetName(), - response.getSpecies(), - response.getBreed(), + response.getPetSpecies(), + response.getPetBreed(), age, response.getPetStatus(), - response.getPrice().doubleValue() + response.getPetPrice().doubleValue() ); } diff --git a/src/main/java/org/example/petshopdesktop/controllers/ProductController.java b/src/main/java/org/example/petshopdesktop/controllers/ProductController.java index f913f1be..e6168911 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/ProductController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/ProductController.java @@ -287,12 +287,12 @@ public class ProductController { private ProductDTO mapToProductDTO(ProductResponse response) { return new ProductDTO( - response.getId().intValue(), - response.getProductName(), - response.getPrice().doubleValue(), + response.getProdId().intValue(), + response.getProdName(), + response.getProdPrice().doubleValue(), 0, response.getCategoryName(), - response.getDescription() + response.getProdDesc() ); } diff --git a/src/main/java/org/example/petshopdesktop/controllers/PurchaseOrderController.java b/src/main/java/org/example/petshopdesktop/controllers/PurchaseOrderController.java index c0caeff9..71ec81ec 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/PurchaseOrderController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/PurchaseOrderController.java @@ -112,7 +112,7 @@ public class PurchaseOrderController { private PurchaseOrderDTO mapToPurchaseOrderDTO(PurchaseOrderResponse response) { return new PurchaseOrderDTO( - response.getId(), + response.getPurchaseOrderId(), response.getSupplierName(), response.getOrderDate() != null ? response.getOrderDate().toString() : "", response.getOrderStatus() diff --git a/src/main/java/org/example/petshopdesktop/controllers/SaleController.java b/src/main/java/org/example/petshopdesktop/controllers/SaleController.java index d22e3f86..2d956ddf 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/SaleController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/SaleController.java @@ -178,11 +178,11 @@ public class SaleController { ObservableList products = FXCollections.observableArrayList(); for (ProductResponse pr : productResponses) { products.add(new Product( - pr.getId().intValue(), - pr.getProductName(), - pr.getPrice().doubleValue(), + pr.getProdId().intValue(), + pr.getProdName(), + pr.getProdPrice().doubleValue(), 0, - pr.getDescription() + pr.getProdDesc() )); } cbProduct.setItems(products); @@ -216,14 +216,16 @@ public class SaleController { if (sale.getItems() != null && !sale.getItems().isEmpty()) { for (SaleItemResponse item : sale.getItems()) { + double unitPrice = item.getUnitPrice() != null ? item.getUnitPrice().doubleValue() : 0.0; + double lineTotal = unitPrice * item.getQuantity(); lineItems.add(new SaleLineItem( - sale.getId().intValue(), + sale.getSaleId().intValue(), saleDate, sale.getEmployeeName(), item.getProductName(), item.getQuantity(), - item.getUnitPrice().doubleValue(), - item.getLineTotal().doubleValue(), + unitPrice, + lineTotal, sale.getPaymentMethod(), sale.getIsRefund() != null && sale.getIsRefund() )); @@ -334,15 +336,14 @@ public class SaleController { List itemRequests = new ArrayList<>(); for (SaleCartItem cartItem : cartItems) { SaleItemRequest itemRequest = new SaleItemRequest(); - itemRequest.setProductId((long) cartItem.getProdId()); + itemRequest.setProdId((long) cartItem.getProdId()); itemRequest.setQuantity(cartItem.getQuantity()); - itemRequest.setUnitPrice(BigDecimal.valueOf(cartItem.getUnitPrice())); itemRequests.add(itemRequest); } request.setItems(itemRequests); SaleResponse response = SaleApi.getInstance().createSale(request); - showInfo("Sale saved", "Sale ID " + response.getId() + " was created."); + showInfo("Sale saved", "Sale ID " + response.getSaleId() + " was created."); cartItems.clear(); updateCartTotal(); diff --git a/src/main/java/org/example/petshopdesktop/controllers/ServiceController.java b/src/main/java/org/example/petshopdesktop/controllers/ServiceController.java index 493d893b..d0a3049e 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/ServiceController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/ServiceController.java @@ -223,11 +223,11 @@ public class ServiceController { private ServiceDTO mapToServiceDTO(ServiceResponse response) { return new ServiceDTO( - response.getId().intValue(), + response.getServiceId().intValue(), response.getServiceName(), - response.getDescription(), - 0, - response.getPrice().doubleValue() + response.getServiceDesc(), + response.getServiceDuration() != null ? response.getServiceDuration() : 0, + response.getServicePrice().doubleValue() ); } } \ No newline at end of file diff --git a/src/main/java/org/example/petshopdesktop/controllers/SupplierController.java b/src/main/java/org/example/petshopdesktop/controllers/SupplierController.java index 144c85ea..4df26941 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/SupplierController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/SupplierController.java @@ -285,18 +285,18 @@ public class SupplierController { } private Supplier mapToSupplier(SupplierResponse response) { - String contactPerson = response.getContactPerson() != null ? response.getContactPerson() : ""; + String contactPerson = response.getSupContactFirstName() + " " + response.getSupContactLastName() != null ? response.getSupContactFirstName() + " " + response.getSupContactLastName() : ""; String[] nameParts = contactPerson.split(" ", 2); String firstName = nameParts.length > 0 ? nameParts[0] : ""; String lastName = nameParts.length > 1 ? nameParts[1] : ""; return new Supplier( - response.getId().intValue(), - response.getSupplierName(), + response.getSupId().intValue(), + response.getSupCompany(), firstName, lastName, - response.getEmail(), - response.getPhone() + response.getSupEmail(), + response.getSupPhone() ); } diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/InventoryDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/InventoryDialogController.java index 3a0b1518..0b410186 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/InventoryDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/InventoryDialogController.java @@ -74,11 +74,11 @@ public class InventoryDialogController { ObservableList products = FXCollections.observableArrayList(); for (ProductResponse pr : productResponses) { products.add(new Product( - pr.getId().intValue(), - pr.getProductName(), - pr.getPrice().doubleValue(), + pr.getProdId().intValue(), + pr.getProdName(), + pr.getProdPrice().doubleValue(), 0, - pr.getDescription() + pr.getProdDesc() )); } cbProduct.setItems(products); @@ -127,14 +127,14 @@ public class InventoryDialogController { try { InventoryRequest request = new InventoryRequest(); Product selectedProduct = cbProduct.getSelectionModel().getSelectedItem(); - request.setProductId((long) selectedProduct.getProdId()); + request.setProdId((long) selectedProduct.getProdId()); int quantity; try { quantity = Integer.parseInt(txtQuantity.getText()); } catch (NumberFormatException e) { throw new IllegalArgumentException("Invalid quantity format"); } - request.setStockQuantity(quantity); + request.setQuantity(quantity); if (mode.equals("Add")) { InventoryApi.getInstance().createInventory(request); diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/PetDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/PetDialogController.java index 1ea93d3e..7d210e73 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/PetDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/PetDialogController.java @@ -143,11 +143,11 @@ public class PetDialogController { private PetRequest buildPetRequest() { PetRequest request = new PetRequest(); request.setPetName(txtPetName.getText()); - request.setSpecies(txtPetSpecies.getText()); - request.setBreed(txtPetBreed.getText()); + request.setPetSpecies(txtPetSpecies.getText()); + request.setPetBreed(txtPetBreed.getText()); request.setPetStatus(cbPetStatus.getValue()); try { - request.setPrice(new BigDecimal(txtPetPrice.getText())); + request.setPetPrice(new BigDecimal(txtPetPrice.getText())); } catch (NumberFormatException e) { throw new IllegalArgumentException("Invalid price format"); } @@ -159,7 +159,6 @@ public class PetDialogController { throw new IllegalArgumentException("Invalid age format"); } LocalDate dateOfBirth = LocalDate.now().minusYears(age); - request.setDateOfBirth(dateOfBirth); return request; } diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductDialogController.java index b35cd57e..25fe1da8 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ProductDialogController.java @@ -111,16 +111,16 @@ public class ProductDialogController { if (errorMsg.isEmpty()) { try { ProductRequest request = new ProductRequest(); - request.setProductName(txtProdName.getText()); + request.setProdName(txtProdName.getText()); BigDecimal price; try { price = new BigDecimal(txtProdPrice.getText()); } catch (NumberFormatException e) { throw new IllegalArgumentException("Invalid price format"); } - request.setPrice(price); + request.setProdPrice(price); request.setCategoryId(cbProdCategory.getSelectionModel().getSelectedItem().getId()); - request.setDescription(txtProdDesc.getText()); + request.setProdDesc(txtProdDesc.getText()); if (mode.equals("Add")) { ProductApi.getInstance().createProduct(request); diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/RefundDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/RefundDialogController.java index 0343b27b..e7a5e218 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/RefundDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/RefundDialogController.java @@ -171,7 +171,7 @@ public class RefundDialogController { } int alreadyRefunded = refundItems.stream() - .filter(r -> r.getProdId() == selected.getId().intValue()) + .filter(r -> r.getProdId() == selected.getSaleItemId().intValue()) .mapToInt(RefundItem::getQuantity) .sum(); @@ -200,7 +200,7 @@ public class RefundDialogController { } refundItems.add(new RefundItem( - selected.getId().intValue(), + selected.getSaleItemId().intValue(), selected.getProductName(), quantity, selected.getUnitPrice().doubleValue() @@ -248,7 +248,7 @@ public class RefundDialogController { Alert confirm = new Alert(Alert.AlertType.CONFIRMATION); confirm.setTitle("Confirm Refund"); - confirm.setHeaderText("Process refund for sale ID " + currentSale.getId() + "?"); + confirm.setHeaderText("Process refund for sale ID " + currentSale.getSaleId() + "?"); confirm.setContentText("Refund amount: " + lblRefundTotal.getText()); Optional confirmResult = confirm.showAndWait(); @@ -261,14 +261,13 @@ public class RefundDialogController { request.setStoreId(storeId); request.setPaymentMethod(payment); request.setIsRefund(true); - request.setOriginalSaleId(currentSale.getId()); + request.setOriginalSaleId(currentSale.getSaleId()); List items = new ArrayList<>(); for (RefundItem item : refundItems) { SaleItemRequest saleItem = new SaleItemRequest(); - saleItem.setProductId((long) item.getProdId()); + saleItem.setProdId((long) item.getProdId()); saleItem.setQuantity(-item.getQuantity()); - saleItem.setUnitPrice(BigDecimal.valueOf(item.getUnitPrice())); items.add(saleItem); } request.setItems(items); @@ -278,7 +277,7 @@ public class RefundDialogController { Alert success = new Alert(Alert.AlertType.INFORMATION); success.setTitle("Refund Processed"); success.setHeaderText(null); - success.setContentText("Refund ID " + refundResponse.getId() + " was created successfully."); + success.setContentText("Refund ID " + refundResponse.getSaleId() + " was created successfully."); success.showAndWait(); closeDialog(); diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ServiceDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ServiceDialogController.java index 8e61169f..26f13b0f 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ServiceDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/ServiceDialogController.java @@ -116,10 +116,13 @@ public class ServiceDialogController { } try { + int durationMinutes = (hours * 60) + minutes; + ServiceRequest request = new ServiceRequest(); request.setServiceName(name); - request.setDescription(desc); - request.setPrice(BigDecimal.valueOf(price)); + request.setServiceDesc(desc); + request.setServicePrice(BigDecimal.valueOf(price)); + request.setServiceDuration(durationMinutes); if (mode.equals("Add")) { ServiceApi.getInstance().createService(request); diff --git a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/SupplierDialogController.java b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/SupplierDialogController.java index b54e3b31..8b61daca 100644 --- a/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/SupplierDialogController.java +++ b/src/main/java/org/example/petshopdesktop/controllers/dialogcontrollers/SupplierDialogController.java @@ -147,10 +147,11 @@ public class SupplierDialogController { */ private SupplierRequest createSupplierRequest(){ SupplierRequest request = new SupplierRequest(); - request.setSupplierName(txtCompanyName.getText()); - request.setContactPerson(txtContactFirstName.getText() + " " + txtContactLastName.getText()); - request.setEmail(txtEmail.getText()); - request.setPhone(txtPhone.getText()); + request.setSupCompany(txtCompanyName.getText()); + request.setSupContactFirstName(txtContactFirstName.getText()); + request.setSupContactLastName(txtContactLastName.getText()); + request.setSupEmail(txtEmail.getText()); + request.setSupPhone(txtPhone.getText()); return request; }