1
.gitignore
vendored
1
.gitignore
vendored
@@ -40,3 +40,4 @@ build/
|
|||||||
|
|
||||||
## Database related
|
## Database related
|
||||||
connectionpetstore.properties
|
connectionpetstore.properties
|
||||||
|
.idea/workspace.xml
|
||||||
|
|||||||
394
Petstoredata.sql
394
Petstoredata.sql
@@ -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');
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
url=jdbc:mysql://127.0.0.1:3306/Petstoredb?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
|
|
||||||
user=petapp
|
|
||||||
password=petapppass
|
|
||||||
@@ -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:
|
|
||||||
|
|
||||||
71
log.txt
71
log.txt
@@ -45,3 +45,74 @@ 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
|
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-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
|
||||||
|
[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<org.example.petshopdesktop.api.dto.product.ProductResponse>` 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<org.example.petshopdesktop.api.dto.sale.SaleResponse>` 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<org.example.petshopdesktop.api.dto.appointment.AppointmentResponse>` 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<org.example.petshopdesktop.api.dto.service.ServiceResponse>` 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<org.example.petshopdesktop.api.dto.service.ServiceResponse>` 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<org.example.petshopdesktop.api.dto.pet.PetResponse>` 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<org.example.petshopdesktop.api.dto.pet.PetResponse>` 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<org.example.petshopdesktop.api.dto.adoption.AdoptionResponse>` 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<org.example.petshopdesktop.api.dto.product.ProductResponse>` 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
|
||||||
|
|||||||
21
pom.xml
21
pom.xml
@@ -40,9 +40,24 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.mysql</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
<artifactId>mysql-connector-j</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
<version>9.3.0</version>
|
<version>2.18.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||||
|
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||||
|
<version>2.18.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-core</artifactId>
|
||||||
|
<version>2.18.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-annotations</artifactId>
|
||||||
|
<version>2.18.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,11 @@ module org.example.petshopdesktop {
|
|||||||
requires javafx.controls;
|
requires javafx.controls;
|
||||||
requires javafx.fxml;
|
requires javafx.fxml;
|
||||||
requires java.sql;
|
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.DTOs to javafx.base;
|
||||||
opens org.example.petshopdesktop.models 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.controllers to javafx.fxml;
|
||||||
opens org.example.petshopdesktop.auth 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;
|
||||||
exports org.example.petshopdesktop.controllers;
|
exports org.example.petshopdesktop.controllers;
|
||||||
exports org.example.petshopdesktop.auth;
|
exports org.example.petshopdesktop.auth;
|
||||||
|
|||||||
@@ -4,21 +4,21 @@ import javafx.beans.property.*;
|
|||||||
|
|
||||||
public class PurchaseOrderDTO {
|
public class PurchaseOrderDTO {
|
||||||
|
|
||||||
private IntegerProperty purchaseOrderId;
|
private LongProperty purchaseOrderId;
|
||||||
private StringProperty supplierName;
|
private StringProperty supplierName;
|
||||||
private StringProperty orderDate;
|
private StringProperty orderDate;
|
||||||
private StringProperty status;
|
private StringProperty status;
|
||||||
|
|
||||||
public PurchaseOrderDTO(int id, String supplierName,
|
public PurchaseOrderDTO(long id, String supplierName,
|
||||||
String orderDate, String status) {
|
String orderDate, String status) {
|
||||||
|
|
||||||
this.purchaseOrderId = new SimpleIntegerProperty(id);
|
this.purchaseOrderId = new SimpleLongProperty(id);
|
||||||
this.supplierName = new SimpleStringProperty(supplierName);
|
this.supplierName = new SimpleStringProperty(supplierName);
|
||||||
this.orderDate = new SimpleStringProperty(orderDate);
|
this.orderDate = new SimpleStringProperty(orderDate);
|
||||||
this.status = new SimpleStringProperty(status);
|
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 getSupplierName() { return supplierName.get(); }
|
||||||
public String getOrderDate() { return orderDate.get(); }
|
public String getOrderDate() { return orderDate.get(); }
|
||||||
public String getStatus() { return status.get(); }
|
public String getStatus() { return status.get(); }
|
||||||
|
|||||||
@@ -4,18 +4,12 @@ import javafx.application.Application;
|
|||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.example.petshopdesktop.database.UserDB;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class PetShopApplication extends Application {
|
public class PetShopApplication extends Application {
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage stage) throws IOException {
|
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"));
|
FXMLLoader fxmlLoader = new FXMLLoader(PetShopApplication.class.getResource("login-view.fxml"));
|
||||||
Scene scene = new Scene(fxmlLoader.load());
|
Scene scene = new Scene(fxmlLoader.load());
|
||||||
stage.setTitle("Pet Shop Manager - Login");
|
stage.setTitle("Pet Shop Manager - Login");
|
||||||
|
|||||||
188
src/main/java/org/example/petshopdesktop/api/ApiClient.java
Normal file
188
src/main/java/org/example/petshopdesktop/api/ApiClient.java
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
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.objectMapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
|
this.baseUrl = ApiConfig.getInstance().getBaseUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ApiClient getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T get(String path, Class<T> 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<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||||
|
|
||||||
|
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<String> 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> T post(String path, Object requestBody, Class<T> 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<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||||
|
|
||||||
|
return handleResponse(response, responseClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T put(String path, Object requestBody, Class<T> 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<String> 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<String> 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<String> 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> T handleResponse(HttpResponse<String> response, Class<T> 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<String> 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) {
|
||||||
|
System.err.println("Error parsing error message: " + e.getMessage());
|
||||||
|
}
|
||||||
|
return "Request failed with status " + response.statusCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjectMapper getObjectMapper() {
|
||||||
|
return objectMapper;
|
||||||
|
}
|
||||||
|
}
|
||||||
34
src/main/java/org/example/petshopdesktop/api/ApiConfig.java
Normal file
34
src/main/java/org/example/petshopdesktop/api/ApiConfig.java
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
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 AdoptionRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.adoption;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
public class AdoptionResponse {
|
||||||
|
private Long adoptionId;
|
||||||
|
private String petName;
|
||||||
|
private String customerName;
|
||||||
|
private LocalDate adoptionDate;
|
||||||
|
private String adoptionStatus;
|
||||||
|
|
||||||
|
public AdoptionResponse() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getAdoptionId() {
|
||||||
|
return adoptionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAdoptionId(Long adoptionId) {
|
||||||
|
this.adoptionId = adoptionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.analytics;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
public class DailySales {
|
||||||
|
private String date;
|
||||||
|
private BigDecimal revenue;
|
||||||
|
private Long salesCount;
|
||||||
|
|
||||||
|
public DailySales() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDate() {
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDate(String date) {
|
||||||
|
this.date = date;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getRevenue() {
|
||||||
|
return revenue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRevenue(BigDecimal revenue) {
|
||||||
|
this.revenue = revenue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getSalesCount() {
|
||||||
|
return salesCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSalesCount(Long salesCount) {
|
||||||
|
this.salesCount = salesCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.analytics;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class DashboardResponse {
|
||||||
|
private SalesSummary salesSummary;
|
||||||
|
private InventorySummary inventorySummary;
|
||||||
|
private List<TopProduct> topProducts;
|
||||||
|
private List<DailySales> dailySales;
|
||||||
|
|
||||||
|
public DashboardResponse() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public SalesSummary getSalesSummary() {
|
||||||
|
return salesSummary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSalesSummary(SalesSummary salesSummary) {
|
||||||
|
this.salesSummary = salesSummary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InventorySummary getInventorySummary() {
|
||||||
|
return inventorySummary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInventorySummary(InventorySummary inventorySummary) {
|
||||||
|
this.inventorySummary = inventorySummary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TopProduct> getTopProducts() {
|
||||||
|
return topProducts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTopProducts(List<TopProduct> topProducts) {
|
||||||
|
this.topProducts = topProducts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DailySales> getDailySales() {
|
||||||
|
return dailySales;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDailySales(List<DailySales> dailySales) {
|
||||||
|
this.dailySales = dailySales;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.analytics;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
public class TopProduct {
|
||||||
|
private Long productId;
|
||||||
|
private String productName;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProductName(String productName) {
|
||||||
|
this.productName = productName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getQuantitySold() {
|
||||||
|
return quantitySold;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQuantitySold(Long quantitySold) {
|
||||||
|
this.quantitySold = quantitySold;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getRevenue() {
|
||||||
|
return revenue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRevenue(BigDecimal revenue) {
|
||||||
|
this.revenue = revenue;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.appointment;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class AppointmentRequest {
|
||||||
|
private List<Long> petIds;
|
||||||
|
private Long customerId;
|
||||||
|
private Long serviceId;
|
||||||
|
private LocalDate appointmentDate;
|
||||||
|
private LocalTime appointmentTime;
|
||||||
|
private String appointmentStatus;
|
||||||
|
|
||||||
|
public AppointmentRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Long> getPetIds() {
|
||||||
|
return petIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPetIds(List<Long> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.appointment;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalTime;
|
||||||
|
|
||||||
|
public class AppointmentResponse {
|
||||||
|
private Long appointmentId;
|
||||||
|
private String customerName;
|
||||||
|
private java.util.List<String> petNames;
|
||||||
|
private String serviceName;
|
||||||
|
private LocalDate appointmentDate;
|
||||||
|
private LocalTime appointmentTime;
|
||||||
|
private String appointmentStatus;
|
||||||
|
|
||||||
|
public AppointmentResponse() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getAppointmentId() {
|
||||||
|
return appointmentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAppointmentId(Long appointmentId) {
|
||||||
|
this.appointmentId = appointmentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCustomerName() {
|
||||||
|
return customerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomerName(String customerName) {
|
||||||
|
this.customerName = customerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public java.util.List<String> getPetNames() {
|
||||||
|
return petNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPetNames(java.util.List<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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.auth;
|
||||||
|
|
||||||
|
public class LoginResponse {
|
||||||
|
private String token;
|
||||||
|
private String username;
|
||||||
|
private String role;
|
||||||
|
|
||||||
|
public LoginResponse() {
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.auth;
|
||||||
|
|
||||||
|
public class UserInfoResponse {
|
||||||
|
private Long id;
|
||||||
|
private String username;
|
||||||
|
private String role;
|
||||||
|
|
||||||
|
public UserInfoResponse() {
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.common;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class BulkDeleteRequest {
|
||||||
|
private List<Long> ids;
|
||||||
|
|
||||||
|
public BulkDeleteRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public BulkDeleteRequest(List<Long> ids) {
|
||||||
|
this.ids = ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Long> getIds() {
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIds(List<Long> ids) {
|
||||||
|
this.ids = ids;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.common;
|
||||||
|
|
||||||
|
public class DropdownOption {
|
||||||
|
private Long id;
|
||||||
|
private String label;
|
||||||
|
|
||||||
|
public DropdownOption() {
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
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<T> {
|
||||||
|
private List<T> content;
|
||||||
|
|
||||||
|
@JsonProperty("number")
|
||||||
|
private int pageNumber;
|
||||||
|
|
||||||
|
@JsonProperty("size")
|
||||||
|
private int pageSize;
|
||||||
|
|
||||||
|
private long totalElements;
|
||||||
|
private int totalPages;
|
||||||
|
private boolean last;
|
||||||
|
|
||||||
|
public PageResponse() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<T> getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(List<T> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.inventory;
|
||||||
|
|
||||||
|
public class InventoryRequest {
|
||||||
|
private Long prodId;
|
||||||
|
private Integer quantity;
|
||||||
|
|
||||||
|
public InventoryRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getProdId() {
|
||||||
|
return prodId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProdId(Long prodId) {
|
||||||
|
this.prodId = prodId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getQuantity() {
|
||||||
|
return quantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQuantity(Integer quantity) {
|
||||||
|
this.quantity = quantity;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.inventory;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
public class InventoryResponse {
|
||||||
|
private Long inventoryId;
|
||||||
|
private Long prodId;
|
||||||
|
private String productName;
|
||||||
|
private String categoryName;
|
||||||
|
private Integer quantity;
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
|
||||||
|
public InventoryResponse() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getInventoryId() {
|
||||||
|
return inventoryId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInventoryId(Long inventoryId) {
|
||||||
|
this.inventoryId = inventoryId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getProdId() {
|
||||||
|
return prodId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProdId(Long prodId) {
|
||||||
|
this.prodId = prodId;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 Integer getQuantity() {
|
||||||
|
return quantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQuantity(Integer quantity) {
|
||||||
|
this.quantity = quantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.pet;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
public class PetRequest {
|
||||||
|
private String petName;
|
||||||
|
private String petSpecies;
|
||||||
|
private String petBreed;
|
||||||
|
private Integer petAge;
|
||||||
|
private String petStatus;
|
||||||
|
private BigDecimal petPrice;
|
||||||
|
|
||||||
|
public PetRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPetName() {
|
||||||
|
return petName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPetName(String petName) {
|
||||||
|
this.petName = petName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPetSpecies() {
|
||||||
|
return petSpecies;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPetSpecies(String petSpecies) {
|
||||||
|
this.petSpecies = petSpecies;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPetBreed() {
|
||||||
|
return petBreed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPetBreed(String petBreed) {
|
||||||
|
this.petBreed = petBreed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getPetAge() {
|
||||||
|
return petAge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPetAge(Integer petAge) {
|
||||||
|
this.petAge = petAge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPetStatus() {
|
||||||
|
return petStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPetStatus(String petStatus) {
|
||||||
|
this.petStatus = petStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getPetPrice() {
|
||||||
|
return petPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPetPrice(BigDecimal petPrice) {
|
||||||
|
this.petPrice = petPrice;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.pet;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
public class PetResponse {
|
||||||
|
private Long petId;
|
||||||
|
private String petName;
|
||||||
|
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 getPetId() {
|
||||||
|
return petId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPetId(Long petId) {
|
||||||
|
this.petId = petId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPetName() {
|
||||||
|
return petName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPetName(String petName) {
|
||||||
|
this.petName = petName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPetSpecies() {
|
||||||
|
return petSpecies;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPetSpecies(String petSpecies) {
|
||||||
|
this.petSpecies = petSpecies;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPetBreed() {
|
||||||
|
return petBreed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPetBreed(String petBreed) {
|
||||||
|
this.petBreed = petBreed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getPetAge() {
|
||||||
|
return petAge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPetAge(Integer petAge) {
|
||||||
|
this.petAge = petAge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPetStatus() {
|
||||||
|
return petStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.product;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
public class ProductRequest {
|
||||||
|
private String prodName;
|
||||||
|
private Long categoryId;
|
||||||
|
private BigDecimal prodPrice;
|
||||||
|
private String prodDesc;
|
||||||
|
|
||||||
|
public ProductRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProdName() {
|
||||||
|
return prodName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProdName(String prodName) {
|
||||||
|
this.prodName = prodName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getCategoryId() {
|
||||||
|
return categoryId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCategoryId(Long categoryId) {
|
||||||
|
this.categoryId = categoryId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getProdPrice() {
|
||||||
|
return prodPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProdPrice(BigDecimal prodPrice) {
|
||||||
|
this.prodPrice = prodPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProdDesc() {
|
||||||
|
return prodDesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProdDesc(String prodDesc) {
|
||||||
|
this.prodDesc = prodDesc;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.product;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
public class ProductResponse {
|
||||||
|
private Long prodId;
|
||||||
|
private String prodName;
|
||||||
|
private String categoryName;
|
||||||
|
private BigDecimal prodPrice;
|
||||||
|
private String prodDesc;
|
||||||
|
|
||||||
|
public ProductResponse() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getProdId() {
|
||||||
|
return prodId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProdId(Long prodId) {
|
||||||
|
this.prodId = prodId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProdName() {
|
||||||
|
return prodName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProdName(String prodName) {
|
||||||
|
this.prodName = prodName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCategoryName() {
|
||||||
|
return categoryName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCategoryName(String categoryName) {
|
||||||
|
this.categoryName = categoryName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getProdPrice() {
|
||||||
|
return prodPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProdPrice(BigDecimal prodPrice) {
|
||||||
|
this.prodPrice = prodPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProdDesc() {
|
||||||
|
return prodDesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProdDesc(String prodDesc) {
|
||||||
|
this.prodDesc = prodDesc;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.productsupplier;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
public class ProductSupplierRequest {
|
||||||
|
private Long productId;
|
||||||
|
private Long supplierId;
|
||||||
|
private BigDecimal cost;
|
||||||
|
|
||||||
|
public ProductSupplierRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
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 getCost() {
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCost(BigDecimal cost) {
|
||||||
|
this.cost = cost;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.productsupplier;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
public class ProductSupplierResponse {
|
||||||
|
private Long productId;
|
||||||
|
private Long supplierId;
|
||||||
|
private String productName;
|
||||||
|
private String supplierName;
|
||||||
|
private BigDecimal cost;
|
||||||
|
|
||||||
|
public ProductSupplierResponse() {
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProductName(String productName) {
|
||||||
|
this.productName = productName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSupplierName() {
|
||||||
|
return supplierName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSupplierName(String supplierName) {
|
||||||
|
this.supplierName = supplierName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getCost() {
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCost(BigDecimal cost) {
|
||||||
|
this.cost = cost;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.purchaseorder;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
public class PurchaseOrderResponse {
|
||||||
|
private Long purchaseOrderId;
|
||||||
|
private String supplierName;
|
||||||
|
private LocalDate orderDate;
|
||||||
|
private LocalDate expectedDeliveryDate;
|
||||||
|
private String orderStatus;
|
||||||
|
private BigDecimal totalAmount;
|
||||||
|
|
||||||
|
public PurchaseOrderResponse() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getPurchaseOrderId() {
|
||||||
|
return purchaseOrderId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPurchaseOrderId(Long purchaseOrderId) {
|
||||||
|
this.purchaseOrderId = purchaseOrderId;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.sale;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
public class SaleItemRequest {
|
||||||
|
private Long prodId;
|
||||||
|
private Integer quantity;
|
||||||
|
|
||||||
|
public SaleItemRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getProdId() {
|
||||||
|
return prodId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProdId(Long prodId) {
|
||||||
|
this.prodId = prodId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getQuantity() {
|
||||||
|
return quantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQuantity(Integer quantity) {
|
||||||
|
this.quantity = quantity;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.sale;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
public class SaleItemResponse {
|
||||||
|
private Long saleItemId;
|
||||||
|
private Long prodId;
|
||||||
|
private String productName;
|
||||||
|
private Integer quantity;
|
||||||
|
private BigDecimal unitPrice;
|
||||||
|
|
||||||
|
public SaleItemResponse() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getSaleItemId() {
|
||||||
|
return saleItemId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSaleItemId(Long saleItemId) {
|
||||||
|
this.saleItemId = saleItemId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getProdId() {
|
||||||
|
return prodId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProdId(Long prodId) {
|
||||||
|
this.prodId = prodId;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.sale;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SaleRequest {
|
||||||
|
private Long storeId;
|
||||||
|
private String paymentMethod;
|
||||||
|
private List<SaleItemRequest> items;
|
||||||
|
private Boolean isRefund;
|
||||||
|
private Long originalSaleId;
|
||||||
|
|
||||||
|
public SaleRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
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<SaleItemRequest> getItems() {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setItems(List<SaleItemRequest> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.sale;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SaleResponse {
|
||||||
|
private Long saleId;
|
||||||
|
private String employeeName;
|
||||||
|
private String storeName;
|
||||||
|
private LocalDateTime saleDate;
|
||||||
|
private BigDecimal totalAmount;
|
||||||
|
private String paymentMethod;
|
||||||
|
private Boolean isRefund;
|
||||||
|
private Long originalSaleId;
|
||||||
|
private List<SaleItemResponse> items;
|
||||||
|
|
||||||
|
public SaleResponse() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getSaleId() {
|
||||||
|
return saleId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSaleId(Long saleId) {
|
||||||
|
this.saleId = saleId;
|
||||||
|
}
|
||||||
|
|
||||||
|
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<SaleItemResponse> getItems() {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setItems(List<SaleItemResponse> items) {
|
||||||
|
this.items = items;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.service;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
public class ServiceRequest {
|
||||||
|
private String serviceName;
|
||||||
|
private BigDecimal servicePrice;
|
||||||
|
private String serviceDesc;
|
||||||
|
private Integer serviceDuration;
|
||||||
|
|
||||||
|
public ServiceRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServiceName() {
|
||||||
|
return serviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServiceName(String serviceName) {
|
||||||
|
this.serviceName = serviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getServicePrice() {
|
||||||
|
return servicePrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServicePrice(BigDecimal servicePrice) {
|
||||||
|
this.servicePrice = servicePrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServiceDesc() {
|
||||||
|
return serviceDesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServiceDesc(String serviceDesc) {
|
||||||
|
this.serviceDesc = serviceDesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getServiceDuration() {
|
||||||
|
return serviceDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServiceDuration(Integer serviceDuration) {
|
||||||
|
this.serviceDuration = serviceDuration;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.service;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
public class ServiceResponse {
|
||||||
|
private Long serviceId;
|
||||||
|
private String serviceName;
|
||||||
|
private BigDecimal servicePrice;
|
||||||
|
private String serviceDesc;
|
||||||
|
private Integer serviceDuration;
|
||||||
|
|
||||||
|
public ServiceResponse() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getServiceId() {
|
||||||
|
return serviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServiceId(Long serviceId) {
|
||||||
|
this.serviceId = serviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServiceName() {
|
||||||
|
return serviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServiceName(String serviceName) {
|
||||||
|
this.serviceName = serviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getServicePrice() {
|
||||||
|
return servicePrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServicePrice(BigDecimal servicePrice) {
|
||||||
|
this.servicePrice = servicePrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServiceDesc() {
|
||||||
|
return serviceDesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServiceDesc(String serviceDesc) {
|
||||||
|
this.serviceDesc = serviceDesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getServiceDuration() {
|
||||||
|
return serviceDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServiceDuration(Integer serviceDuration) {
|
||||||
|
this.serviceDuration = serviceDuration;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.supplier;
|
||||||
|
|
||||||
|
public class SupplierRequest {
|
||||||
|
private String supCompany;
|
||||||
|
private String supContactFirstName;
|
||||||
|
private String supContactLastName;
|
||||||
|
private String supPhone;
|
||||||
|
private String supEmail;
|
||||||
|
private String address;
|
||||||
|
|
||||||
|
public SupplierRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSupCompany() {
|
||||||
|
return supCompany;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSupCompany(String supCompany) {
|
||||||
|
this.supCompany = supCompany;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSupContactFirstName() {
|
||||||
|
return supContactFirstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSupContactFirstName(String supContactFirstName) {
|
||||||
|
this.supContactFirstName = supContactFirstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSupContactLastName() {
|
||||||
|
return supContactLastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSupContactLastName(String supContactLastName) {
|
||||||
|
this.supContactLastName = supContactLastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSupPhone() {
|
||||||
|
return supPhone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSupPhone(String supPhone) {
|
||||||
|
this.supPhone = supPhone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSupEmail() {
|
||||||
|
return supEmail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSupEmail(String supEmail) {
|
||||||
|
this.supEmail = supEmail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddress(String address) {
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.supplier;
|
||||||
|
|
||||||
|
public class SupplierResponse {
|
||||||
|
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 getSupId() {
|
||||||
|
return supId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSupId(Long supId) {
|
||||||
|
this.supId = supId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSupCompany() {
|
||||||
|
return supCompany;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSupCompany(String supCompany) {
|
||||||
|
this.supCompany = supCompany;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSupContactFirstName() {
|
||||||
|
return supContactFirstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSupContactFirstName(String supContactFirstName) {
|
||||||
|
this.supContactFirstName = supContactFirstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSupContactLastName() {
|
||||||
|
return supContactLastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSupContactLastName(String supContactLastName) {
|
||||||
|
this.supContactLastName = supContactLastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSupPhone() {
|
||||||
|
return supPhone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSupPhone(String supPhone) {
|
||||||
|
this.supPhone = supPhone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSupEmail() {
|
||||||
|
return supEmail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSupEmail(String supEmail) {
|
||||||
|
this.supEmail = supEmail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddress(String address) {
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package org.example.petshopdesktop.api.dto.user;
|
||||||
|
|
||||||
|
public class UserRequest {
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
private String fullName;
|
||||||
|
private String email;
|
||||||
|
private String role;
|
||||||
|
private Boolean active;
|
||||||
|
|
||||||
|
public UserRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
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 getFullName() {
|
||||||
|
return fullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFullName(String fullName) {
|
||||||
|
this.fullName = fullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
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 email;
|
||||||
|
private String role;
|
||||||
|
private Boolean active;
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
|
||||||
|
public UserResponse() {
|
||||||
|
}
|
||||||
|
|
||||||
|
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 getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getUpdatedAt() {
|
||||||
|
return updatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdatedAt(LocalDateTime updatedAt) {
|
||||||
|
this.updatedAt = updatedAt;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
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 org.example.petshopdesktop.api.dto.common.PageResponse;
|
||||||
|
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
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<AdoptionResponse> listAdoptions(String query) throws Exception {
|
||||||
|
String path = "/api/v1/adoptions?page=0&size=1000";
|
||||||
|
if (query != null && !query.isEmpty()) {
|
||||||
|
path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
String response = apiClient.getRawResponse(path);
|
||||||
|
PageResponse<AdoptionResponse> pageResponse = apiClient.getObjectMapper().readValue(
|
||||||
|
response,
|
||||||
|
new TypeReference<PageResponse<AdoptionResponse>>() {}
|
||||||
|
);
|
||||||
|
if (pageResponse == null) {
|
||||||
|
throw new IllegalStateException("Null response from adoptions endpoint");
|
||||||
|
}
|
||||||
|
return pageResponse.getContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Long> ids) throws Exception {
|
||||||
|
apiClient.deleteWithBody("/api/v1/adoptions", new BulkDeleteRequest(ids));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
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 org.example.petshopdesktop.api.dto.common.PageResponse;
|
||||||
|
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
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<AppointmentResponse> listAppointments(String query) throws Exception {
|
||||||
|
String path = "/api/v1/appointments?page=0&size=1000";
|
||||||
|
if (query != null && !query.isEmpty()) {
|
||||||
|
path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
String response = apiClient.getRawResponse(path);
|
||||||
|
PageResponse<AppointmentResponse> pageResponse = apiClient.getObjectMapper().readValue(
|
||||||
|
response,
|
||||||
|
new TypeReference<PageResponse<AppointmentResponse>>() {}
|
||||||
|
);
|
||||||
|
if (pageResponse == null) {
|
||||||
|
throw new IllegalStateException("Null response from appointments endpoint");
|
||||||
|
}
|
||||||
|
return pageResponse.getContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Long> ids) throws Exception {
|
||||||
|
apiClient.deleteWithBody("/api/v1/appointments", new BulkDeleteRequest(ids));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
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<DropdownOption> getCategories() throws Exception {
|
||||||
|
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<List<DropdownOption>>() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DropdownOption> getProducts() throws Exception {
|
||||||
|
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<List<DropdownOption>>() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DropdownOption> getSuppliers() throws Exception {
|
||||||
|
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<List<DropdownOption>>() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DropdownOption> getServices() throws Exception {
|
||||||
|
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<List<DropdownOption>>() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DropdownOption> getCustomers() throws Exception {
|
||||||
|
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<List<DropdownOption>>() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DropdownOption> getPets() throws Exception {
|
||||||
|
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<List<DropdownOption>>() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DropdownOption> getStores() throws Exception {
|
||||||
|
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<List<DropdownOption>>() {});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
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 {
|
||||||
|
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<InventoryResponse> listInventory(String query) throws Exception {
|
||||||
|
String path = "/api/v1/inventory?page=0&size=1000";
|
||||||
|
if (query != null && !query.isEmpty()) {
|
||||||
|
path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
String response = apiClient.getRawResponse(path);
|
||||||
|
PageResponse<InventoryResponse> pageResponse = apiClient.getObjectMapper().readValue(
|
||||||
|
response,
|
||||||
|
new TypeReference<PageResponse<InventoryResponse>>() {}
|
||||||
|
);
|
||||||
|
if (pageResponse == null) {
|
||||||
|
throw new IllegalStateException("Null response from inventory endpoint");
|
||||||
|
}
|
||||||
|
return pageResponse.getContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
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 {
|
||||||
|
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<PetResponse> listPets(String query) throws Exception {
|
||||||
|
String path = "/api/v1/pets?page=0&size=1000";
|
||||||
|
if (query != null && !query.isEmpty()) {
|
||||||
|
path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
String response = apiClient.getRawResponse(path);
|
||||||
|
PageResponse<PetResponse> pageResponse = apiClient.getObjectMapper().readValue(
|
||||||
|
response,
|
||||||
|
new TypeReference<PageResponse<PetResponse>>() {}
|
||||||
|
);
|
||||||
|
if (pageResponse == null) {
|
||||||
|
throw new IllegalStateException("Null response from pets endpoint");
|
||||||
|
}
|
||||||
|
return pageResponse.getContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Long> ids) throws Exception {
|
||||||
|
apiClient.deleteWithBody("/api/v1/pets", new BulkDeleteRequest(ids));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
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 {
|
||||||
|
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<ProductResponse> listProducts(String query) throws Exception {
|
||||||
|
String path = "/api/v1/products?page=0&size=1000";
|
||||||
|
if (query != null && !query.isEmpty()) {
|
||||||
|
path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
String response = apiClient.getRawResponse(path);
|
||||||
|
PageResponse<ProductResponse> pageResponse = apiClient.getObjectMapper().readValue(
|
||||||
|
response,
|
||||||
|
new TypeReference<PageResponse<ProductResponse>>() {}
|
||||||
|
);
|
||||||
|
if (pageResponse == null) {
|
||||||
|
throw new IllegalStateException("Null response from products endpoint");
|
||||||
|
}
|
||||||
|
return pageResponse.getContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Long> ids) throws Exception {
|
||||||
|
apiClient.deleteWithBody("/api/v1/products", new BulkDeleteRequest(ids));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
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 {
|
||||||
|
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<ProductSupplierResponse> listProductSuppliers(String query) throws Exception {
|
||||||
|
String path = "/api/v1/product-suppliers?page=0&size=1000";
|
||||||
|
if (query != null && !query.isEmpty()) {
|
||||||
|
path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
String response = apiClient.getRawResponse(path);
|
||||||
|
PageResponse<ProductSupplierResponse> pageResponse = apiClient.getObjectMapper().readValue(
|
||||||
|
response,
|
||||||
|
new TypeReference<PageResponse<ProductSupplierResponse>>() {}
|
||||||
|
);
|
||||||
|
if (pageResponse == null) {
|
||||||
|
throw new IllegalStateException("Null response from product-suppliers endpoint");
|
||||||
|
}
|
||||||
|
return pageResponse.getContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProductSupplierResponse createProductSupplier(ProductSupplierRequest request) throws Exception {
|
||||||
|
return apiClient.post("/api/v1/product-suppliers", 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 deleteProductSupplier(Long productId, Long supplierId) throws Exception {
|
||||||
|
apiClient.delete("/api/v1/product-suppliers/" + productId + "/" + supplierId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
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 {
|
||||||
|
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<PurchaseOrderResponse> listPurchaseOrders(String query) throws Exception {
|
||||||
|
String path = "/api/v1/purchase-orders?page=0&size=1000";
|
||||||
|
if (query != null && !query.isEmpty()) {
|
||||||
|
path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
String response = apiClient.getRawResponse(path);
|
||||||
|
PageResponse<PurchaseOrderResponse> pageResponse = apiClient.getObjectMapper().readValue(
|
||||||
|
response,
|
||||||
|
new TypeReference<PageResponse<PurchaseOrderResponse>>() {}
|
||||||
|
);
|
||||||
|
if (pageResponse == null) {
|
||||||
|
throw new IllegalStateException("Null response from purchase-orders endpoint");
|
||||||
|
}
|
||||||
|
return pageResponse.getContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
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 {
|
||||||
|
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<SaleResponse> 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=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
String response = apiClient.getRawResponse(path);
|
||||||
|
PageResponse<SaleResponse> pageResponse = apiClient.getObjectMapper().readValue(
|
||||||
|
response,
|
||||||
|
new TypeReference<PageResponse<SaleResponse>>() {}
|
||||||
|
);
|
||||||
|
if (pageResponse == null) {
|
||||||
|
throw new IllegalStateException("Null response from sales endpoint");
|
||||||
|
}
|
||||||
|
return pageResponse.getContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
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 {
|
||||||
|
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<ServiceResponse> listServices(String query) throws Exception {
|
||||||
|
String path = "/api/v1/services?page=0&size=1000";
|
||||||
|
if (query != null && !query.isEmpty()) {
|
||||||
|
path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
String response = apiClient.getRawResponse(path);
|
||||||
|
PageResponse<ServiceResponse> pageResponse = apiClient.getObjectMapper().readValue(
|
||||||
|
response,
|
||||||
|
new TypeReference<PageResponse<ServiceResponse>>() {}
|
||||||
|
);
|
||||||
|
if (pageResponse == null) {
|
||||||
|
throw new IllegalStateException("Null response from services endpoint");
|
||||||
|
}
|
||||||
|
return pageResponse.getContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Long> ids) throws Exception {
|
||||||
|
apiClient.deleteWithBody("/api/v1/services", new BulkDeleteRequest(ids));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
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 {
|
||||||
|
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<SupplierResponse> listSuppliers(String query) throws Exception {
|
||||||
|
String path = "/api/v1/suppliers?page=0&size=1000";
|
||||||
|
if (query != null && !query.isEmpty()) {
|
||||||
|
path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
String response = apiClient.getRawResponse(path);
|
||||||
|
PageResponse<SupplierResponse> pageResponse = apiClient.getObjectMapper().readValue(
|
||||||
|
response,
|
||||||
|
new TypeReference<PageResponse<SupplierResponse>>() {}
|
||||||
|
);
|
||||||
|
if (pageResponse == null) {
|
||||||
|
throw new IllegalStateException("Null response from suppliers endpoint");
|
||||||
|
}
|
||||||
|
return pageResponse.getContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Long> ids) throws Exception {
|
||||||
|
apiClient.deleteWithBody("/api/v1/suppliers", new BulkDeleteRequest(ids));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
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 {
|
||||||
|
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<UserResponse> listUsers(String query) throws Exception {
|
||||||
|
String path = "/api/v1/users?page=0&size=1000";
|
||||||
|
if (query != null && !query.isEmpty()) {
|
||||||
|
path += "&q=" + URLEncoder.encode(query, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
String response = apiClient.getRawResponse(path);
|
||||||
|
PageResponse<UserResponse> pageResponse = apiClient.getObjectMapper().readValue(
|
||||||
|
response,
|
||||||
|
new TypeReference<PageResponse<UserResponse>>() {}
|
||||||
|
);
|
||||||
|
if (pageResponse == null) {
|
||||||
|
throw new IllegalStateException("Null response from users endpoint");
|
||||||
|
}
|
||||||
|
return pageResponse.getContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserResponse createUser(UserRequest request) throws Exception {
|
||||||
|
return apiClient.post("/api/v1/users", request, UserResponse.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,11 +3,13 @@ package org.example.petshopdesktop.auth;
|
|||||||
public class UserSession {
|
public class UserSession {
|
||||||
private static UserSession instance;
|
private static UserSession instance;
|
||||||
|
|
||||||
private Integer userId;
|
private Long userId;
|
||||||
private Integer employeeId;
|
private Long employeeId;
|
||||||
private String username;
|
private String username;
|
||||||
private String employeeName;
|
private String employeeName;
|
||||||
private Role role;
|
private Role role;
|
||||||
|
private String jwtToken;
|
||||||
|
private Long storeId;
|
||||||
|
|
||||||
private UserSession() {}
|
private UserSession() {}
|
||||||
|
|
||||||
@@ -18,12 +20,13 @@ public class UserSession {
|
|||||||
return instance;
|
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.userId = userId;
|
||||||
this.employeeId = employeeId;
|
this.employeeId = userId;
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.employeeName = employeeName;
|
this.employeeName = username;
|
||||||
this.role = role;
|
this.role = role;
|
||||||
|
this.jwtToken = jwtToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void logout() {
|
public void logout() {
|
||||||
@@ -32,13 +35,15 @@ public class UserSession {
|
|||||||
this.username = null;
|
this.username = null;
|
||||||
this.employeeName = null;
|
this.employeeName = null;
|
||||||
this.role = null;
|
this.role = null;
|
||||||
|
this.jwtToken = null;
|
||||||
|
this.storeId = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getUserId() {
|
public Long getUserId() {
|
||||||
return userId;
|
return userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getEmployeeId() {
|
public Long getEmployeeId() {
|
||||||
return employeeId;
|
return employeeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,6 +59,18 @@ public class UserSession {
|
|||||||
return role;
|
return role;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getJwtToken() {
|
||||||
|
return jwtToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getStoreId() {
|
||||||
|
return storeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStoreId(Long storeId) {
|
||||||
|
this.storeId = storeId;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isLoggedIn() {
|
public boolean isLoggedIn() {
|
||||||
return username != null && role != null;
|
return username != null && role != null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.example.petshopdesktop.controllers;
|
package org.example.petshopdesktop.controllers;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
@@ -10,15 +11,16 @@ import javafx.scene.control.*;
|
|||||||
import javafx.scene.control.cell.PropertyValueFactory;
|
import javafx.scene.control.cell.PropertyValueFactory;
|
||||||
import javafx.stage.Modality;
|
import javafx.stage.Modality;
|
||||||
import javafx.stage.Stage;
|
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.controllers.dialogcontrollers.AdoptionDialogController;
|
||||||
import org.example.petshopdesktop.database.AdoptionDB;
|
|
||||||
import org.example.petshopdesktop.models.Adoption;
|
import org.example.petshopdesktop.models.Adoption;
|
||||||
import org.example.petshopdesktop.util.ActivityLogger;
|
import org.example.petshopdesktop.util.ActivityLogger;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.sql.SQLException;
|
import java.util.List;
|
||||||
import java.sql.SQLIntegrityConstraintViolationException;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class AdoptionController {
|
public class AdoptionController {
|
||||||
|
|
||||||
@@ -35,7 +37,7 @@ public class AdoptionController {
|
|||||||
private TableColumn<Adoption, Integer> colAdoptionId;
|
private TableColumn<Adoption, Integer> colAdoptionId;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private TableColumn<Adoption, Integer> colPetId;
|
private TableColumn<Adoption, String> colPetId;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private TableColumn<Adoption, String> colCustomerName;
|
private TableColumn<Adoption, String> colCustomerName;
|
||||||
@@ -66,7 +68,7 @@ public class AdoptionController {
|
|||||||
tvAdoptions.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.MULTIPLE);
|
tvAdoptions.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.MULTIPLE);
|
||||||
|
|
||||||
colAdoptionId.setCellValueFactory(new PropertyValueFactory<>("adoptionId"));
|
colAdoptionId.setCellValueFactory(new PropertyValueFactory<>("adoptionId"));
|
||||||
colPetId.setCellValueFactory(new PropertyValueFactory<>("petId"));
|
colPetId.setCellValueFactory(new PropertyValueFactory<>("petName"));
|
||||||
colCustomerName.setCellValueFactory(new PropertyValueFactory<>("customerName"));
|
colCustomerName.setCellValueFactory(new PropertyValueFactory<>("customerName"));
|
||||||
colAdoptionDate.setCellValueFactory(new PropertyValueFactory<>("adoptionDate"));
|
colAdoptionDate.setCellValueFactory(new PropertyValueFactory<>("adoptionDate"));
|
||||||
colAdoptionFee.setCellValueFactory(new PropertyValueFactory<>("adoptionFee"));
|
colAdoptionFee.setCellValueFactory(new PropertyValueFactory<>("adoptionFee"));
|
||||||
@@ -118,47 +120,24 @@ public class AdoptionController {
|
|||||||
|
|
||||||
//if confirmed, start deletion
|
//if confirmed, start deletion
|
||||||
if (result.isPresent() && result.get() == ButtonType.OK) {
|
if (result.isPresent() && result.get() == ButtonType.OK) {
|
||||||
int successCount = 0;
|
List<Long> ids = selectedAdoptions.stream()
|
||||||
int failCount = 0;
|
.map(a -> (long) a.getAdoptionId())
|
||||||
StringBuilder errors = new StringBuilder();
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
for (Adoption adoption : selectedAdoptions) {
|
|
||||||
try {
|
try {
|
||||||
int numRows = AdoptionDB.deleteAdoption(adoption.getAdoptionId());
|
AdoptionApi.getInstance().deleteAdoptions(ids);
|
||||||
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) {
|
|
||||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||||
alert.setHeaderText("Database Operation Confirmed");
|
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();
|
alert.showAndWait();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,35 +160,55 @@ public class AdoptionController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void displayFilteredAdoptions(String filter) {
|
private void displayFilteredAdoptions(String filter) {
|
||||||
data.clear();
|
|
||||||
try {
|
|
||||||
if (txtSearch.getText() == null || txtSearch.getText().isEmpty()) {
|
if (txtSearch.getText() == null || txtSearch.getText().isEmpty()) {
|
||||||
displayAdoptions();
|
displayAdoptions();
|
||||||
} else {
|
} else {
|
||||||
data = AdoptionDB.getFilteredAdoptions(filter);
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
List<AdoptionResponse> adoptions = AdoptionApi.getInstance().listAdoptions(filter);
|
||||||
|
List<Adoption> adoptionList = adoptions.stream()
|
||||||
|
.map(this::mapToAdoption)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
data.setAll(adoptionList);
|
||||||
tvAdoptions.setItems(data);
|
tvAdoptions.setItems(data);
|
||||||
}
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||||
ActivityLogger.getInstance().logException(
|
ActivityLogger.getInstance().logException(
|
||||||
"AdoptionController.displayFilteredAdoptions",
|
"AdoptionController.displayFilteredAdoptions",
|
||||||
e,
|
e,
|
||||||
"Filtering adoptions with filter: " + filter);
|
"Filtering adoptions with filter: " + filter);
|
||||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
});
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayAdoptions() {
|
private void displayAdoptions() {
|
||||||
data.clear();
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
data = AdoptionDB.getAdoptions();
|
List<AdoptionResponse> adoptions = AdoptionApi.getInstance().listAdoptions(null);
|
||||||
} catch (SQLException e) {
|
List<Adoption> 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(
|
ActivityLogger.getInstance().logException(
|
||||||
"AdoptionController.displayAdoptions",
|
"AdoptionController.displayAdoptions",
|
||||||
e,
|
e,
|
||||||
"Fetching adoption data for table display");
|
"Fetching adoption data for table display");
|
||||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
});
|
||||||
}
|
}
|
||||||
tvAdoptions.setItems(data);
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openDialog(Adoption adoption, String mode) {
|
private void openDialog(Adoption adoption, String mode) {
|
||||||
@@ -244,4 +243,17 @@ public class AdoptionController {
|
|||||||
btnEdit.setDisable(true);
|
btnEdit.setDisable(true);
|
||||||
txtSearch.setText("");
|
txtSearch.setText("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Adoption mapToAdoption(AdoptionResponse response) {
|
||||||
|
return new Adoption(
|
||||||
|
response.getAdoptionId().intValue(),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
response.getPetName(),
|
||||||
|
response.getCustomerName(),
|
||||||
|
response.getAdoptionDate() != null ? response.getAdoptionDate().toString() : "",
|
||||||
|
0.0,
|
||||||
|
response.getAdoptionStatus()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,25 @@
|
|||||||
package org.example.petshopdesktop.controllers;
|
package org.example.petshopdesktop.controllers;
|
||||||
|
|
||||||
import javafx.collections.ObservableList;
|
import javafx.application.Platform;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.chart.*;
|
import javafx.scene.chart.*;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import org.example.petshopdesktop.auth.UserSession;
|
import org.example.petshopdesktop.api.dto.analytics.DailySales;
|
||||||
import org.example.petshopdesktop.database.SaleDB;
|
import org.example.petshopdesktop.api.dto.analytics.DashboardResponse;
|
||||||
import org.example.petshopdesktop.models.analytics.*;
|
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 org.example.petshopdesktop.util.ActivityLogger;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.Locale;
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class AnalyticsController {
|
public class AnalyticsController {
|
||||||
|
|
||||||
@@ -78,79 +84,119 @@ public class AnalyticsController {
|
|||||||
|
|
||||||
private void loadAnalyticsData() {
|
private void loadAnalyticsData() {
|
||||||
lblError.setVisible(false);
|
lblError.setVisible(false);
|
||||||
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
loadSummaryData();
|
DashboardResponse dashboard = AnalyticsApi.getInstance().getDashboard(30, 10);
|
||||||
loadSalesOverTime();
|
List<SaleResponse> sales = SaleApi.getInstance().listSales(0, Integer.MAX_VALUE, null);
|
||||||
loadTopProductsByRevenue();
|
|
||||||
loadTopProductsByQuantity();
|
Platform.runLater(() -> {
|
||||||
loadPaymentMethodDistribution();
|
try {
|
||||||
loadEmployeePerformance();
|
loadSummaryData(dashboard);
|
||||||
|
loadSalesOverTime(dashboard);
|
||||||
|
loadTopProductsByRevenue(dashboard);
|
||||||
|
loadTopProductsByQuantity(dashboard);
|
||||||
|
loadPaymentMethodDistribution(sales);
|
||||||
|
loadEmployeePerformance(sales);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ActivityLogger.getInstance().logException("AnalyticsController.loadAnalyticsData", e, "Loading analytics data");
|
ActivityLogger.getInstance().logException("AnalyticsController.loadAnalyticsData", e, "Loading analytics data");
|
||||||
lblError.setText("Error loading analytics data. Please try again.");
|
lblError.setText("Error loading analytics data. Please try again.");
|
||||||
lblError.setVisible(true);
|
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() throws Exception {
|
private void loadSummaryData(DashboardResponse dashboard) throws Exception {
|
||||||
SalesSummary summary = SaleDB.getSalesSummary();
|
if (dashboard != null) {
|
||||||
if (summary != null) {
|
BigDecimal totalRevenue = BigDecimal.ZERO;
|
||||||
lblTotalRevenue.setText(currency.format(summary.getTotalRevenue()));
|
Long totalSales = 0L;
|
||||||
lblTotalTransactions.setText(wholeNumber.format(summary.getTotalTransactions()));
|
Long totalProducts = 0L;
|
||||||
lblAvgTransaction.setText(currency.format(summary.getAvgTransactionValue()));
|
|
||||||
lblTotalItems.setText(wholeNumber.format(summary.getTotalItemsSold()));
|
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));
|
||||||
|
|
||||||
|
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 loadSalesOverTime() throws Exception {
|
private void loadSalesOverTime(DashboardResponse dashboard) throws Exception {
|
||||||
ObservableList<DailySalesData> data = SaleDB.getDailySalesRevenue();
|
List<DailySales> dailySales = dashboard.getDailySales() != null ? dashboard.getDailySales() : new ArrayList<>();
|
||||||
XYChart.Series<String, Number> series = new XYChart.Series<>();
|
XYChart.Series<String, Number> series = new XYChart.Series<>();
|
||||||
series.setName("Daily Revenue");
|
series.setName("Daily Revenue");
|
||||||
|
|
||||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd");
|
for (DailySales dailySale : dailySales) {
|
||||||
for (DailySalesData dailySale : data) {
|
String dateStr = dailySale.getDate();
|
||||||
String dateStr = dailySale.getDate().format(formatter);
|
BigDecimal revenue = dailySale.getRevenue() != null ? dailySale.getRevenue() : BigDecimal.ZERO;
|
||||||
series.getData().add(new XYChart.Data<>(dateStr, dailySale.getRevenue()));
|
series.getData().add(new XYChart.Data<>(dateStr, revenue));
|
||||||
}
|
}
|
||||||
|
|
||||||
chartSalesOverTime.getData().clear();
|
chartSalesOverTime.getData().clear();
|
||||||
chartSalesOverTime.getData().add(series);
|
chartSalesOverTime.getData().add(series);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadTopProductsByRevenue() throws Exception {
|
private void loadTopProductsByRevenue(DashboardResponse dashboard) throws Exception {
|
||||||
ObservableList<ProductSalesData> data = SaleDB.getTopProductsByRevenue(10);
|
List<TopProduct> topProducts = dashboard.getTopProducts() != null ? dashboard.getTopProducts() : new ArrayList<>();
|
||||||
XYChart.Series<Number, String> series = new XYChart.Series<>();
|
XYChart.Series<Number, String> series = new XYChart.Series<>();
|
||||||
series.setName("Revenue");
|
series.setName("Revenue");
|
||||||
|
|
||||||
for (ProductSalesData product : data) {
|
for (TopProduct product : topProducts) {
|
||||||
series.getData().add(new XYChart.Data<>(product.getTotalRevenue(), product.getProductName()));
|
BigDecimal revenue = product.getRevenue() != null ? product.getRevenue() : BigDecimal.ZERO;
|
||||||
|
series.getData().add(new XYChart.Data<>(revenue, product.getProductName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
chartTopRevenue.getData().clear();
|
chartTopRevenue.getData().clear();
|
||||||
chartTopRevenue.getData().add(series);
|
chartTopRevenue.getData().add(series);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadTopProductsByQuantity() throws Exception {
|
private void loadTopProductsByQuantity(DashboardResponse dashboard) throws Exception {
|
||||||
ObservableList<ProductSalesData> data = SaleDB.getTopProductsByQuantity(10);
|
List<TopProduct> topProducts = dashboard.getTopProducts() != null ? dashboard.getTopProducts() : new ArrayList<>();
|
||||||
XYChart.Series<Number, String> series = new XYChart.Series<>();
|
XYChart.Series<Number, String> series = new XYChart.Series<>();
|
||||||
series.setName("Quantity");
|
series.setName("Quantity");
|
||||||
|
|
||||||
for (ProductSalesData product : data) {
|
for (TopProduct product : topProducts) {
|
||||||
series.getData().add(new XYChart.Data<>(product.getTotalQuantity(), product.getProductName()));
|
Long quantitySold = product.getQuantitySold() != null ? product.getQuantitySold() : 0L;
|
||||||
|
series.getData().add(new XYChart.Data<>(quantitySold, product.getProductName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
chartTopQuantity.getData().clear();
|
chartTopQuantity.getData().clear();
|
||||||
chartTopQuantity.getData().add(series);
|
chartTopQuantity.getData().add(series);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadPaymentMethodDistribution() throws Exception {
|
private void loadPaymentMethodDistribution(List<SaleResponse> sales) throws Exception {
|
||||||
ObservableList<PaymentMethodData> data = SaleDB.getPaymentMethodDistribution();
|
Map<String, Long> 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();
|
chartPaymentMethods.getData().clear();
|
||||||
|
|
||||||
for (PaymentMethodData payment : data) {
|
for (Map.Entry<String, Long> entry : paymentMethodCount.entrySet()) {
|
||||||
PieChart.Data slice = new PieChart.Data(
|
PieChart.Data slice = new PieChart.Data(
|
||||||
payment.getPaymentMethod() + " (" + payment.getTransactionCount() + ")",
|
entry.getKey() + " (" + entry.getValue() + ")",
|
||||||
payment.getTransactionCount()
|
entry.getValue()
|
||||||
);
|
);
|
||||||
chartPaymentMethods.getData().add(slice);
|
chartPaymentMethods.getData().add(slice);
|
||||||
}
|
}
|
||||||
@@ -158,13 +204,20 @@ public class AnalyticsController {
|
|||||||
chartPaymentMethods.setLabelsVisible(false);
|
chartPaymentMethods.setLabelsVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadEmployeePerformance() throws Exception {
|
private void loadEmployeePerformance(List<SaleResponse> sales) throws Exception {
|
||||||
ObservableList<EmployeeSalesData> data = SaleDB.getEmployeeSalesPerformance();
|
Map<String, Double> 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<String, Number> series = new XYChart.Series<>();
|
XYChart.Series<String, Number> series = new XYChart.Series<>();
|
||||||
series.setName("Revenue");
|
series.setName("Revenue");
|
||||||
|
|
||||||
for (EmployeeSalesData employee : data) {
|
for (Map.Entry<String, Double> entry : employeeRevenue.entrySet()) {
|
||||||
series.getData().add(new XYChart.Data<>(employee.getEmployeeName(), employee.getTotalRevenue()));
|
series.getData().add(new XYChart.Data<>(entry.getKey(), entry.getValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
chartEmployeePerformance.getData().clear();
|
chartEmployeePerformance.getData().clear();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.example.petshopdesktop.controllers;
|
package org.example.petshopdesktop.controllers;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.collections.transformation.FilteredList;
|
import javafx.collections.transformation.FilteredList;
|
||||||
@@ -13,10 +14,14 @@ import javafx.stage.Modality;
|
|||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
import org.example.petshopdesktop.DTOs.AppointmentDTO;
|
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.controllers.dialogcontrollers.AppointmentDialogController;
|
||||||
import org.example.petshopdesktop.database.AppointmentDB;
|
|
||||||
import org.example.petshopdesktop.util.ActivityLogger;
|
import org.example.petshopdesktop.util.ActivityLogger;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class AppointmentController {
|
public class AppointmentController {
|
||||||
|
|
||||||
@FXML private TableView<AppointmentDTO> tvAppointments;
|
@FXML private TableView<AppointmentDTO> tvAppointments;
|
||||||
@@ -71,41 +76,50 @@ public class AppointmentController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void loadAppointments(){
|
private void loadAppointments(){
|
||||||
|
new Thread(() -> {
|
||||||
try{
|
try{
|
||||||
appointments.setAll(AppointmentDB.getAppointmentDTOs());
|
List<AppointmentResponse> responses = AppointmentApi.getInstance().listAppointments(null);
|
||||||
|
List<AppointmentDTO> appointmentDTOs = responses.stream()
|
||||||
|
.map(this::mapToAppointmentDTO)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
appointments.setAll(appointmentDTOs);
|
||||||
|
});
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
|
Platform.runLater(() -> {
|
||||||
ActivityLogger.getInstance().logException(
|
ActivityLogger.getInstance().logException(
|
||||||
"AppointmentController.loadAppointments",
|
"AppointmentController.loadAppointments",
|
||||||
e,
|
e,
|
||||||
"Loading appointments for table display");
|
"Loading appointments for table display");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyFilter(String text) {
|
private void applyFilter(String text) {
|
||||||
if (filtered == null) {
|
String query = text == null || text.trim().isEmpty() ? null : text.trim();
|
||||||
return;
|
new Thread(() -> {
|
||||||
}
|
try {
|
||||||
|
List<AppointmentResponse> responses = AppointmentApi.getInstance().listAppointments(query);
|
||||||
|
List<AppointmentDTO> appointmentDTOs = responses.stream()
|
||||||
|
.map(this::mapToAppointmentDTO)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
String q = text == null ? "" : text.trim().toLowerCase();
|
Platform.runLater(() -> {
|
||||||
if (q.isEmpty()) {
|
appointments.setAll(appointmentDTOs);
|
||||||
filtered.setPredicate(a -> true);
|
});
|
||||||
return;
|
} catch (Exception e) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
ActivityLogger.getInstance().logException(
|
||||||
|
"AppointmentController.applyFilter",
|
||||||
|
e,
|
||||||
|
String.format("Filtering appointments with query: %s", query));
|
||||||
|
e.printStackTrace();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
}).start();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
@@ -145,35 +159,24 @@ public class AppointmentController {
|
|||||||
|
|
||||||
//if confirmed, start deletion
|
//if confirmed, start deletion
|
||||||
if (result.isPresent() && result.get() == ButtonType.OK) {
|
if (result.isPresent() && result.get() == ButtonType.OK) {
|
||||||
int successCount = 0;
|
List<Long> ids = selectedAppointments.stream()
|
||||||
int failCount = 0;
|
.map(a -> (long) a.getAppointmentId())
|
||||||
StringBuilder errors = new StringBuilder();
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
for (AppointmentDTO appointment : selectedAppointments) {
|
|
||||||
try {
|
try {
|
||||||
AppointmentDB.deleteAppointment(appointment.getAppointmentId());
|
AppointmentApi.getInstance().deleteAppointments(ids);
|
||||||
successCount++;
|
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||||
|
alert.setHeaderText("Database Operation Confirmed");
|
||||||
|
alert.setContentText("Successfully deleted " + ids.size() + " appointment(s)");
|
||||||
|
alert.showAndWait();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ActivityLogger.getInstance().logException(
|
ActivityLogger.getInstance().logException(
|
||||||
"AppointmentController.btnDeleteClicked",
|
"AppointmentController.btnDeleteClicked",
|
||||||
e,
|
e,
|
||||||
String.format("Attempting to delete appointment ID %d", appointment.getAppointmentId()));
|
"Deleting appointments");
|
||||||
failCount++;
|
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||||
errors.append("Failed to delete appointment ID ").append(appointment.getAppointmentId()).append("\n");
|
alert.setHeaderText("Delete Operation Failed");
|
||||||
}
|
alert.setContentText(e.getMessage());
|
||||||
}
|
|
||||||
|
|
||||||
//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) {
|
|
||||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
|
||||||
alert.setHeaderText("Database Operation Confirmed");
|
|
||||||
alert.setContentText("Successfully deleted " + successCount + " appointment(s)");
|
|
||||||
alert.showAndWait();
|
alert.showAndWait();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,4 +228,19 @@ public class AppointmentController {
|
|||||||
alert.setContentText(msg);
|
alert.setContentText(msg);
|
||||||
alert.showAndWait();
|
alert.showAndWait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private AppointmentDTO mapToAppointmentDTO(AppointmentResponse response) {
|
||||||
|
return new AppointmentDTO(
|
||||||
|
response.getAppointmentId().intValue(),
|
||||||
|
0,
|
||||||
|
response.getCustomerName(),
|
||||||
|
0,
|
||||||
|
String.join(", ", response.getPetNames()),
|
||||||
|
0,
|
||||||
|
response.getServiceName(),
|
||||||
|
response.getAppointmentDate().toString(),
|
||||||
|
response.getAppointmentTime().toString(),
|
||||||
|
response.getAppointmentStatus()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.example.petshopdesktop.controllers;
|
package org.example.petshopdesktop.controllers;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
@@ -10,15 +11,16 @@ import javafx.scene.control.*;
|
|||||||
import javafx.scene.control.cell.PropertyValueFactory;
|
import javafx.scene.control.cell.PropertyValueFactory;
|
||||||
import javafx.stage.Modality;
|
import javafx.stage.Modality;
|
||||||
import javafx.stage.Stage;
|
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.controllers.dialogcontrollers.InventoryDialogController;
|
||||||
import org.example.petshopdesktop.database.InventoryDB;
|
|
||||||
import org.example.petshopdesktop.models.Inventory;
|
import org.example.petshopdesktop.models.Inventory;
|
||||||
import org.example.petshopdesktop.util.ActivityLogger;
|
import org.example.petshopdesktop.util.ActivityLogger;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.sql.SQLException;
|
import java.util.List;
|
||||||
import java.sql.SQLIntegrityConstraintViolationException;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class InventoryController {
|
public class InventoryController {
|
||||||
|
|
||||||
@@ -58,11 +60,9 @@ public class InventoryController {
|
|||||||
//Loads upon view bootup
|
//Loads upon view bootup
|
||||||
@FXML
|
@FXML
|
||||||
void initialize() {
|
void initialize() {
|
||||||
//Buttons disabled until row is selected
|
|
||||||
btnEdit.setDisable(true);
|
btnEdit.setDisable(true);
|
||||||
btnDelete.setDisable(true);
|
btnDelete.setDisable(true);
|
||||||
//Enable multiple selection
|
tvInventory.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.SINGLE);
|
||||||
tvInventory.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.MULTIPLE);
|
|
||||||
|
|
||||||
colInventoryId.setCellValueFactory(new PropertyValueFactory<>("inventoryId"));
|
colInventoryId.setCellValueFactory(new PropertyValueFactory<>("inventoryId"));
|
||||||
colProductId.setCellValueFactory(new PropertyValueFactory<>("prodId"));
|
colProductId.setCellValueFactory(new PropertyValueFactory<>("prodId"));
|
||||||
@@ -71,19 +71,16 @@ public class InventoryController {
|
|||||||
|
|
||||||
displayInventory();
|
displayInventory();
|
||||||
|
|
||||||
//Enables buttons when row is selected
|
|
||||||
tvInventory.getSelectionModel().selectedItemProperty().addListener(
|
tvInventory.getSelectionModel().selectedItemProperty().addListener(
|
||||||
(observable, oldValue, newValue) -> {
|
(observable, oldValue, newValue) -> {
|
||||||
btnEdit.setDisable(false);
|
btnEdit.setDisable(false);
|
||||||
btnDelete.setDisable(false);
|
btnDelete.setDisable(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
//Filter as user types
|
|
||||||
txtSearch.textProperty().addListener((observable, oldValue, newValue) -> {
|
txtSearch.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
displayFilteredInventory(newValue);
|
displayFilteredInventory(newValue);
|
||||||
});
|
});
|
||||||
|
|
||||||
//EventListener for DELETE key
|
|
||||||
tvInventory.setOnKeyPressed(event -> {
|
tvInventory.setOnKeyPressed(event -> {
|
||||||
if (event.getCode() == javafx.scene.input.KeyCode.DELETE) {
|
if (event.getCode() == javafx.scene.input.KeyCode.DELETE) {
|
||||||
if (tvInventory.getSelectionModel().getSelectedItem() != null) {
|
if (tvInventory.getSelectionModel().getSelectedItem() != null) {
|
||||||
@@ -100,71 +97,35 @@ public class InventoryController {
|
|||||||
openDialog(null, mode);
|
openDialog(null, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Prompts user for confirmation prior to deletion
|
|
||||||
@FXML
|
@FXML
|
||||||
void btnDeleteClicked(ActionEvent event) {
|
void btnDeleteClicked(ActionEvent event) {
|
||||||
//get selected inventory records
|
Inventory selectedInventory = tvInventory.getSelectionModel().getSelectedItem();
|
||||||
var selectedInventory = tvInventory.getSelectionModel().getSelectedItems();
|
if (selectedInventory == null) return;
|
||||||
if (selectedInventory.isEmpty()) return;
|
|
||||||
|
|
||||||
//ask user to confirm
|
|
||||||
Alert question = new Alert(Alert.AlertType.CONFIRMATION);
|
Alert question = new Alert(Alert.AlertType.CONFIRMATION);
|
||||||
question.setHeaderText("Please confirm delete");
|
question.setHeaderText("Please confirm delete");
|
||||||
String message = selectedInventory.size() == 1
|
question.setContentText("Are you sure you want to delete this inventory record?");
|
||||||
? "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.getDialogPane().lookupButton(ButtonType.OK).requestFocus();
|
question.getDialogPane().lookupButton(ButtonType.OK).requestFocus();
|
||||||
Optional<ButtonType> result = question.showAndWait();
|
Optional<ButtonType> result = question.showAndWait();
|
||||||
|
|
||||||
//if confirmed, start deletion
|
|
||||||
if (result.isPresent() && result.get() == ButtonType.OK) {
|
if (result.isPresent() && result.get() == ButtonType.OK) {
|
||||||
int successCount = 0;
|
|
||||||
int failCount = 0;
|
|
||||||
StringBuilder errors = new StringBuilder();
|
|
||||||
|
|
||||||
for (Inventory inventory : selectedInventory) {
|
|
||||||
try {
|
try {
|
||||||
int numRows = InventoryDB.deleteInventory(inventory.getInventoryId());
|
InventoryApi.getInstance().deleteInventory((long) selectedInventory.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) {
|
|
||||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||||
alert.setHeaderText("Database Operation Confirmed");
|
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();
|
alert.showAndWait();
|
||||||
}
|
}
|
||||||
|
|
||||||
//refresh display and reset inputs
|
|
||||||
displayInventory();
|
displayInventory();
|
||||||
btnDelete.setDisable(true);
|
btnDelete.setDisable(true);
|
||||||
btnEdit.setDisable(true);
|
btnEdit.setDisable(true);
|
||||||
@@ -183,66 +144,72 @@ public class InventoryController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Search filter
|
|
||||||
private void displayFilteredInventory(String filter) {
|
private void displayFilteredInventory(String filter) {
|
||||||
data.clear();
|
|
||||||
try {
|
|
||||||
//If search box is empty, display all inventory
|
|
||||||
if (txtSearch.getText() == null || txtSearch.getText().isEmpty()) {
|
if (txtSearch.getText() == null || txtSearch.getText().isEmpty()) {
|
||||||
displayInventory();
|
displayInventory();
|
||||||
}
|
} else {
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
List<InventoryResponse> inventories = InventoryApi.getInstance().listInventory(filter);
|
||||||
|
List<Inventory> inventoryList = inventories.stream()
|
||||||
|
.map(this::mapToInventory)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
else {
|
Platform.runLater(() -> {
|
||||||
data = InventoryDB.getFilteredInventory(filter);
|
data.setAll(inventoryList);
|
||||||
tvInventory.setItems(data);
|
tvInventory.setItems(data);
|
||||||
}
|
});
|
||||||
}
|
} catch (Exception e) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
catch (Exception e) {
|
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||||
ActivityLogger.getInstance().logException(
|
ActivityLogger.getInstance().logException(
|
||||||
"InventoryController.displayFilteredInventory",
|
"InventoryController.displayFilteredInventory",
|
||||||
e,
|
e,
|
||||||
"Filtering inventory with filter: " + filter);
|
String.format("Filtering inventory with keyword: %s", filter));
|
||||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
});
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Displays all records from DB
|
|
||||||
private void displayInventory() {
|
private void displayInventory() {
|
||||||
data.clear();
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
data = InventoryDB.getInventory();
|
List<InventoryResponse> inventories = InventoryApi.getInstance().listInventory(null);
|
||||||
}
|
List<Inventory> inventoryList = inventories.stream()
|
||||||
|
.map(this::mapToInventory)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
catch (SQLException e) {
|
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(
|
ActivityLogger.getInstance().logException(
|
||||||
"InventoryController.displayInventory",
|
"InventoryController.displayInventory",
|
||||||
e,
|
e,
|
||||||
"Fetching inventory data for table display");
|
"Fetching inventory data for table display");
|
||||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
});
|
||||||
}
|
}
|
||||||
tvInventory.setItems(data);
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Opens inventory-dialog-view
|
|
||||||
private void openDialog(Inventory inventory, String mode) {
|
private void openDialog(Inventory inventory, String mode) {
|
||||||
//Opens FXML
|
|
||||||
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/inventory-dialog-view.fxml"));
|
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/inventory-dialog-view.fxml"));
|
||||||
Scene scene = null;
|
Scene scene = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
scene = new Scene(fxmlLoader.load());
|
scene = new Scene(fxmlLoader.load());
|
||||||
}
|
} catch (IOException e) {
|
||||||
|
|
||||||
catch (IOException e) {
|
|
||||||
ActivityLogger.getInstance().logException(
|
ActivityLogger.getInstance().logException(
|
||||||
"InventoryController.openDialog",
|
"InventoryController.openDialog",
|
||||||
e,
|
e,
|
||||||
"Loading inventory dialog in " + mode + " mode");
|
String.format("Loading inventory dialog view in %s mode", mode));
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Passes data and mode to the view
|
|
||||||
InventoryDialogController dialogController = fxmlLoader.getController();
|
InventoryDialogController dialogController = fxmlLoader.getController();
|
||||||
dialogController.setMode(mode);
|
dialogController.setMode(mode);
|
||||||
|
|
||||||
@@ -256,10 +223,22 @@ public class InventoryController {
|
|||||||
dialogStage.setScene(scene);
|
dialogStage.setScene(scene);
|
||||||
dialogStage.showAndWait();
|
dialogStage.showAndWait();
|
||||||
|
|
||||||
//Refresh inventory
|
|
||||||
displayInventory();
|
displayInventory();
|
||||||
btnDelete.setDisable(true);
|
btnDelete.setDisable(true);
|
||||||
btnEdit.setDisable(true);
|
btnEdit.setDisable(true);
|
||||||
txtSearch.setText("");
|
txtSearch.setText("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Inventory mapToInventory(InventoryResponse response) {
|
||||||
|
return new Inventory(
|
||||||
|
response.getInventoryId().intValue(),
|
||||||
|
0,
|
||||||
|
response.getProductName(),
|
||||||
|
response.getCategoryName() != null ? response.getCategoryName() : "",
|
||||||
|
0,
|
||||||
|
"N/A",
|
||||||
|
response.getQuantity() != null ? response.getQuantity() : 0,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,13 +10,17 @@ import javafx.scene.control.PasswordField;
|
|||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
import javafx.stage.Modality;
|
import javafx.stage.Modality;
|
||||||
import javafx.stage.Stage;
|
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.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 org.example.petshopdesktop.util.ActivityLogger;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
import java.util.List;
|
||||||
|
|
||||||
public class LoginController {
|
public class LoginController {
|
||||||
|
|
||||||
@@ -32,15 +36,6 @@ public class LoginController {
|
|||||||
@FXML
|
@FXML
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
lblError.setText("");
|
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
|
@FXML
|
||||||
@@ -54,39 +49,60 @@ public class LoginController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
User user = UserDB.authenticate(username, password);
|
ApiClient apiClient = ApiClient.getInstance();
|
||||||
if (user == null) {
|
|
||||||
lblError.setText("Invalid username or password.");
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("CUSTOMER".equalsIgnoreCase(roleStr)) {
|
||||||
|
lblError.setText("Access Denied: Customer accounts cannot access the desktop application.");
|
||||||
txtPassword.clear();
|
txtPassword.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UserSession.getInstance().login(
|
Role role = Role.valueOf(roleStr.toUpperCase());
|
||||||
user.getUserId(),
|
|
||||||
user.getEmployeeId(),
|
UserSession.getInstance().login(null, username, role, token);
|
||||||
user.getUsername(),
|
|
||||||
user.getEmployeeFullName(),
|
UserInfoResponse userInfo = apiClient.get("/api/v1/auth/me", UserInfoResponse.class);
|
||||||
user.getRole()
|
if (userInfo == null) {
|
||||||
);
|
throw new IllegalStateException("User info is null");
|
||||||
|
}
|
||||||
|
UserSession.getInstance().login(userInfo.getId(), username, role, token);
|
||||||
|
|
||||||
|
List<DropdownOption> stores = DropdownApi.getInstance().getStores();
|
||||||
|
if (stores != null && !stores.isEmpty()) {
|
||||||
|
UserSession.getInstance().setStoreId(stores.get(0).getId());
|
||||||
|
}
|
||||||
|
|
||||||
openMainLayout();
|
openMainLayout();
|
||||||
|
|
||||||
} catch (SQLException e) {
|
} catch (Exception e) {
|
||||||
ActivityLogger.getInstance().logException(
|
ActivityLogger.getInstance().logException(
|
||||||
"LoginController.btnLoginClicked",
|
"LoginController.btnLoginClicked",
|
||||||
e,
|
e,
|
||||||
"Authentication attempt for username: " + username);
|
"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")) {
|
String errorMsg = e.getMessage();
|
||||||
lblError.setText("Database error. Check Docker and connectionpetstore.properties.");
|
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 {
|
} 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.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -173,8 +173,14 @@ public class MainLayoutController {
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
void logoClicked(MouseEvent event) {
|
void logoClicked(MouseEvent event) {
|
||||||
|
UserSession session = UserSession.getInstance();
|
||||||
|
if (session.isAdmin()) {
|
||||||
loadView("analytics-view.fxml");
|
loadView("analytics-view.fxml");
|
||||||
updateButtons(btnAnalytics);
|
updateButtons(btnAnalytics);
|
||||||
|
} else {
|
||||||
|
loadView("sale-view.fxml");
|
||||||
|
updateButtons(btnSalesHistory);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
@@ -201,8 +207,14 @@ public class MainLayoutController {
|
|||||||
public void initialize() {
|
public void initialize() {
|
||||||
applyRBAC();
|
applyRBAC();
|
||||||
|
|
||||||
|
UserSession session = UserSession.getInstance();
|
||||||
|
if (session.isAdmin()) {
|
||||||
loadView("analytics-view.fxml");
|
loadView("analytics-view.fxml");
|
||||||
updateButtons(btnAnalytics);
|
updateButtons(btnAnalytics);
|
||||||
|
} else {
|
||||||
|
loadView("sale-view.fxml");
|
||||||
|
updateButtons(btnSalesHistory);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyRBAC() {
|
private void applyRBAC() {
|
||||||
@@ -241,6 +253,11 @@ public class MainLayoutController {
|
|||||||
separatorAdmin.setManaged(isAdmin);
|
separatorAdmin.setManaged(isAdmin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (btnAnalytics != null) {
|
||||||
|
btnAnalytics.setVisible(isAdmin);
|
||||||
|
btnAnalytics.setManaged(isAdmin);
|
||||||
|
}
|
||||||
|
|
||||||
btnSalesHistory.setText(isAdmin ? "Sales History" : "Sales");
|
btnSalesHistory.setText(isAdmin ? "Sales History" : "Sales");
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.example.petshopdesktop.controllers;
|
package org.example.petshopdesktop.controllers;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
@@ -10,16 +11,18 @@ import javafx.scene.control.*;
|
|||||||
import javafx.scene.control.cell.PropertyValueFactory;
|
import javafx.scene.control.cell.PropertyValueFactory;
|
||||||
import javafx.stage.Modality;
|
import javafx.stage.Modality;
|
||||||
import javafx.stage.Stage;
|
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.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.models.Pet;
|
||||||
import org.example.petshopdesktop.util.ActivityLogger;
|
import org.example.petshopdesktop.util.ActivityLogger;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.sql.SQLException;
|
import java.time.LocalDate;
|
||||||
import java.sql.SQLIntegrityConstraintViolationException;
|
import java.time.Period;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class PetController {
|
public class PetController {
|
||||||
|
|
||||||
@@ -83,48 +86,24 @@ public class PetController {
|
|||||||
|
|
||||||
//if confirmed, start deletion
|
//if confirmed, start deletion
|
||||||
if (result.isPresent() && result.get() == ButtonType.OK) {
|
if (result.isPresent() && result.get() == ButtonType.OK) {
|
||||||
int successCount = 0;
|
List<Long> ids = selectedPets.stream()
|
||||||
int failCount = 0;
|
.map(p -> (long) p.getPetId())
|
||||||
StringBuilder errors = new StringBuilder();
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
for (Pet pet : selectedPets) {
|
|
||||||
try {
|
try {
|
||||||
int numRows = PetDB.deletePet(pet.getPetId());
|
PetApi.getInstance().deletePets(ids);
|
||||||
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) {
|
|
||||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||||
alert.setHeaderText("Database Operation Confirmed");
|
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();
|
alert.showAndWait();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,39 +166,55 @@ public class PetController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void displayFilteredPet(String filter) {
|
private void displayFilteredPet(String filter) {
|
||||||
data.clear();
|
|
||||||
try{
|
|
||||||
if (txtSearch.getText() == null || txtSearch.getText().isEmpty()){
|
if (txtSearch.getText() == null || txtSearch.getText().isEmpty()){
|
||||||
displayPets();
|
displayPets();
|
||||||
}
|
} else {
|
||||||
else {
|
new Thread(() -> {
|
||||||
data = PetDB.getFilteredPets(filter);
|
try {
|
||||||
|
List<PetResponse> pets = PetApi.getInstance().listPets(filter);
|
||||||
|
List<Pet> petList = pets.stream()
|
||||||
|
.map(this::mapToPet)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
data.setAll(petList);
|
||||||
tvPets.setItems(data);
|
tvPets.setItems(data);
|
||||||
}
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||||
ActivityLogger.getInstance().logException(
|
ActivityLogger.getInstance().logException(
|
||||||
"PetController.displayFilteredPet",
|
"PetController.displayFilteredPet",
|
||||||
e,
|
e,
|
||||||
"Filtering pets with filter: " + filter);
|
String.format("Filtering pets with keyword: %s", filter));
|
||||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
});
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayPets() {
|
private void displayPets() {
|
||||||
data.clear();
|
new Thread(() -> {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
data = PetDB.getPets();
|
List<PetResponse> pets = PetApi.getInstance().listPets(null);
|
||||||
}
|
List<Pet> petList = pets.stream()
|
||||||
catch(SQLException e){
|
.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(
|
ActivityLogger.getInstance().logException(
|
||||||
"PetController.displayPets",
|
"PetController.displayPets",
|
||||||
e,
|
e,
|
||||||
"Fetching pet data for table display");
|
"Fetching pet data for table display");
|
||||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
});
|
||||||
}
|
}
|
||||||
|
}).start();
|
||||||
tvPets.setItems(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openDialog(Pet pet, String mode){
|
private void openDialog(Pet pet, String mode){
|
||||||
@@ -261,4 +256,20 @@ public class PetController {
|
|||||||
txtSearch.setText("");
|
txtSearch.setText("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Pet mapToPet(PetResponse response) {
|
||||||
|
int age = 0;
|
||||||
|
if (null != null) {
|
||||||
|
age = Period.between(null, LocalDate.now()).getYears();
|
||||||
|
}
|
||||||
|
return new Pet(
|
||||||
|
response.getPetId().intValue(),
|
||||||
|
response.getPetName(),
|
||||||
|
response.getPetSpecies(),
|
||||||
|
response.getPetBreed(),
|
||||||
|
age,
|
||||||
|
response.getPetStatus(),
|
||||||
|
response.getPetPrice().doubleValue()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.example.petshopdesktop.controllers;
|
package org.example.petshopdesktop.controllers;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
@@ -11,18 +12,16 @@ import javafx.scene.control.cell.PropertyValueFactory;
|
|||||||
import javafx.stage.Modality;
|
import javafx.stage.Modality;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.example.petshopdesktop.DTOs.ProductDTO;
|
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.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 org.example.petshopdesktop.util.ActivityLogger;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.sql.SQLException;
|
import java.util.ArrayList;
|
||||||
import java.sql.SQLIntegrityConstraintViolationException;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The controller for any operations in the products view
|
* The controller for any operations in the products view
|
||||||
@@ -110,22 +109,27 @@ public class ProductController {
|
|||||||
* Display the productDTO to table view
|
* Display the productDTO to table view
|
||||||
*/
|
*/
|
||||||
private void displayProduct(){
|
private void displayProduct(){
|
||||||
//Erase old content
|
new Thread(() -> {
|
||||||
data.clear();
|
|
||||||
|
|
||||||
//get Products from database
|
|
||||||
try {
|
try {
|
||||||
data = ProductDB.getProductDTO();
|
List<ProductResponse> products = ProductApi.getInstance().listProducts(null);
|
||||||
} catch (SQLException e) {
|
List<ProductDTO> 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());
|
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||||
ActivityLogger.getInstance().logException(
|
ActivityLogger.getInstance().logException(
|
||||||
"ProductController.displayProduct",
|
"ProductController.displayProduct",
|
||||||
e,
|
e,
|
||||||
"Fetching product data for table display");
|
"Fetching product data for table display");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
}).start();
|
||||||
//put data in the table
|
|
||||||
tvProducts.setItems(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -160,48 +164,24 @@ public class ProductController {
|
|||||||
|
|
||||||
//if confirmed, start deletion
|
//if confirmed, start deletion
|
||||||
if (result.isPresent() && result.get() == ButtonType.OK) {
|
if (result.isPresent() && result.get() == ButtonType.OK) {
|
||||||
int successCount = 0;
|
List<Long> ids = selectedProducts.stream()
|
||||||
int failCount = 0;
|
.map(p -> (long) p.getProdId())
|
||||||
StringBuilder errors = new StringBuilder();
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
for (ProductDTO product : selectedProducts) {
|
|
||||||
try {
|
try {
|
||||||
int numRows = ProductDB.deleteProduct(product.getProdId());
|
ProductApi.getInstance().deleteProducts(ids);
|
||||||
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) {
|
|
||||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||||
alert.setHeaderText("Database Operation Confirmed");
|
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();
|
alert.showAndWait();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,22 +213,30 @@ public class ProductController {
|
|||||||
* @param filter word to filter table
|
* @param filter word to filter table
|
||||||
*/
|
*/
|
||||||
private void displayFilteredProduct(String filter){
|
private void displayFilteredProduct(String filter){
|
||||||
data.clear();
|
|
||||||
try{
|
|
||||||
if (txtSearch.getText() == null || txtSearch.getText().isEmpty()){
|
if (txtSearch.getText() == null || txtSearch.getText().isEmpty()){
|
||||||
displayProduct(); //If search bar is empty just display everything
|
displayProduct();
|
||||||
}
|
} else {
|
||||||
else{
|
new Thread(() -> {
|
||||||
//Filter the using the keyword
|
try {
|
||||||
data = ProductDB.getFilteredProductDTOs(filter);
|
List<ProductResponse> products = ProductApi.getInstance().listProducts(filter);
|
||||||
|
List<ProductDTO> productDTOs = products.stream()
|
||||||
|
.map(this::mapToProductDTO)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
data.setAll(productDTOs);
|
||||||
tvProducts.setItems(data);
|
tvProducts.setItems(data);
|
||||||
}
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||||
ActivityLogger.getInstance().logException(
|
ActivityLogger.getInstance().logException(
|
||||||
"ProductController.displayFilteredProduct",
|
"ProductController.displayFilteredProduct",
|
||||||
e,
|
e,
|
||||||
String.format("Filtering products with keyword: %s", filter));
|
String.format("Filtering products with keyword: %s", filter));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,4 +285,15 @@ public class ProductController {
|
|||||||
txtSearch.setText("");
|
txtSearch.setText("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ProductDTO mapToProductDTO(ProductResponse response) {
|
||||||
|
return new ProductDTO(
|
||||||
|
response.getProdId().intValue(),
|
||||||
|
response.getProdName(),
|
||||||
|
response.getProdPrice().doubleValue(),
|
||||||
|
0,
|
||||||
|
response.getCategoryName(),
|
||||||
|
response.getProdDesc()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.example.petshopdesktop.controllers;
|
package org.example.petshopdesktop.controllers;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
@@ -10,19 +11,16 @@ import javafx.scene.control.*;
|
|||||||
import javafx.scene.control.cell.PropertyValueFactory;
|
import javafx.scene.control.cell.PropertyValueFactory;
|
||||||
import javafx.stage.Modality;
|
import javafx.stage.Modality;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.example.petshopdesktop.DTOs.ProductDTO;
|
|
||||||
import org.example.petshopdesktop.DTOs.ProductSupplierDTO;
|
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.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 org.example.petshopdesktop.util.ActivityLogger;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.sql.SQLException;
|
import java.util.List;
|
||||||
import java.sql.SQLIntegrityConstraintViolationException;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class ProductSupplierController {
|
public class ProductSupplierController {
|
||||||
|
|
||||||
@@ -107,22 +105,27 @@ public class ProductSupplierController {
|
|||||||
* Display the ProductSupplierDTO to table view
|
* Display the ProductSupplierDTO to table view
|
||||||
*/
|
*/
|
||||||
private void displayProductSupplier() {
|
private void displayProductSupplier() {
|
||||||
//Erase old content
|
new Thread(() -> {
|
||||||
data.clear();
|
|
||||||
|
|
||||||
//get ProductSupplier from database
|
|
||||||
try {
|
try {
|
||||||
data = ProductSupplierDB.getProductSupplierDTO();
|
List<ProductSupplierResponse> productSuppliers = ProductSupplierApi.getInstance().listProductSuppliers(null);
|
||||||
} catch (SQLException e) {
|
List<ProductSupplierDTO> 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(
|
ActivityLogger.getInstance().logException(
|
||||||
"ProductSupplierController.displayProductSupplier",
|
"ProductSupplierController.displayProductSupplier",
|
||||||
e,
|
e,
|
||||||
"Fetching product-supplier data for table display");
|
"Fetching product-supplier data for table display");
|
||||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
});
|
||||||
}
|
}
|
||||||
|
}).start();
|
||||||
//put data in the table
|
|
||||||
tvProductSuppliers.setItems(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -130,22 +133,30 @@ public class ProductSupplierController {
|
|||||||
* @param filter word to filter table
|
* @param filter word to filter table
|
||||||
*/
|
*/
|
||||||
private void displayFilteredProductSupplier(String filter){
|
private void displayFilteredProductSupplier(String filter){
|
||||||
data.clear();
|
|
||||||
try{
|
|
||||||
if (txtSearch.getText() == null || txtSearch.getText().isEmpty()){
|
if (txtSearch.getText() == null || txtSearch.getText().isEmpty()){
|
||||||
displayProductSupplier(); //If search bar is empty just display everything
|
displayProductSupplier();
|
||||||
}
|
} else {
|
||||||
else{
|
new Thread(() -> {
|
||||||
//Filter the using the keyword
|
try {
|
||||||
data = ProductSupplierDB.getFilteredProductSupplierDTO(filter);
|
List<ProductSupplierResponse> productSuppliers = ProductSupplierApi.getInstance().listProductSuppliers(filter);
|
||||||
|
List<ProductSupplierDTO> productSupplierDTOs = productSuppliers.stream()
|
||||||
|
.map(this::mapToProductSupplierDTO)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
data.setAll(productSupplierDTOs);
|
||||||
tvProductSuppliers.setItems(data);
|
tvProductSuppliers.setItems(data);
|
||||||
}
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||||
ActivityLogger.getInstance().logException(
|
ActivityLogger.getInstance().logException(
|
||||||
"ProductSupplierController.displayFilteredProductSupplier",
|
"ProductSupplierController.displayFilteredProductSupplier",
|
||||||
e,
|
e,
|
||||||
"Filtering product-supplier data with filter: " + filter);
|
"Filtering product-supplier data with filter: " + filter);
|
||||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
});
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,52 +192,36 @@ public class ProductSupplierController {
|
|||||||
|
|
||||||
//if confirmed, start deletion
|
//if confirmed, start deletion
|
||||||
if (result.isPresent() && result.get() == ButtonType.OK) {
|
if (result.isPresent() && result.get() == ButtonType.OK) {
|
||||||
int successCount = 0;
|
int deleteCount = 0;
|
||||||
int failCount = 0;
|
Exception lastException = null;
|
||||||
StringBuilder errors = new StringBuilder();
|
|
||||||
|
|
||||||
for (ProductSupplierDTO productSupplier : selectedProductSuppliers) {
|
for (ProductSupplierDTO ps : selectedProductSuppliers) {
|
||||||
try {
|
try {
|
||||||
int numRows = ProductSupplierDB.deleteProductSupplier(productSupplier.getSupId(), productSupplier.getProdId());
|
ProductSupplierApi.getInstance().deleteProductSupplier(
|
||||||
if (numRows > 0) {
|
(long) ps.getProdId(),
|
||||||
successCount++;
|
(long) ps.getSupId()
|
||||||
} else {
|
);
|
||||||
failCount++;
|
deleteCount++;
|
||||||
}
|
} catch (Exception e) {
|
||||||
}
|
lastException = e;
|
||||||
catch (SQLIntegrityConstraintViolationException e){
|
|
||||||
ActivityLogger.getInstance().logException(
|
ActivityLogger.getInstance().logException(
|
||||||
"ProductSupplierController.btnDeleteClicked",
|
"ProductSupplierController.btnDeleteClicked",
|
||||||
e,
|
e,
|
||||||
String.format("Attempting to delete product-supplier - SupID: %d, ProdID: %d - foreign key constraint",
|
"Deleting product-supplier with productId=" + ps.getProdId() + ", supplierId=" + ps.getSupId());
|
||||||
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 (deleteCount > 0) {
|
||||||
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) {
|
|
||||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||||
alert.setHeaderText("Database Operation Confirmed");
|
alert.setHeaderText("Database Operation Confirmed");
|
||||||
alert.setContentText("Successfully deleted " + successCount + " product-supplier(s)");
|
alert.setContentText("Successfully deleted " + deleteCount + " product-supplier(s)");
|
||||||
|
alert.showAndWait();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastException != null && deleteCount < selectedProductSuppliers.size()) {
|
||||||
|
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||||
|
alert.setHeaderText("Delete Operation Partially Failed");
|
||||||
|
alert.setContentText("Deleted " + deleteCount + " of " + selectedProductSuppliers.size() + " product-supplier(s). Last error: " + lastException.getMessage());
|
||||||
alert.showAndWait();
|
alert.showAndWait();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,4 +292,14 @@ public class ProductSupplierController {
|
|||||||
txtSearch.setText("");
|
txtSearch.setText("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ProductSupplierDTO mapToProductSupplierDTO(ProductSupplierResponse response) {
|
||||||
|
return new ProductSupplierDTO(
|
||||||
|
response.getSupplierId().intValue(),
|
||||||
|
response.getProductId().intValue(),
|
||||||
|
response.getSupplierName(),
|
||||||
|
response.getProductName(),
|
||||||
|
response.getCost().doubleValue()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.example.petshopdesktop.controllers;
|
package org.example.petshopdesktop.controllers;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.collections.transformation.FilteredList;
|
import javafx.collections.transformation.FilteredList;
|
||||||
@@ -7,9 +8,13 @@ import javafx.fxml.FXML;
|
|||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.control.cell.PropertyValueFactory;
|
import javafx.scene.control.cell.PropertyValueFactory;
|
||||||
import org.example.petshopdesktop.DTOs.PurchaseOrderDTO;
|
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 org.example.petshopdesktop.util.ActivityLogger;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class PurchaseOrderController {
|
public class PurchaseOrderController {
|
||||||
|
|
||||||
@FXML private Button btnRefresh;
|
@FXML private Button btnRefresh;
|
||||||
@@ -19,7 +24,7 @@ public class PurchaseOrderController {
|
|||||||
|
|
||||||
@FXML private TableView<PurchaseOrderDTO> tvPurchaseOrders;
|
@FXML private TableView<PurchaseOrderDTO> tvPurchaseOrders;
|
||||||
|
|
||||||
@FXML private TableColumn<PurchaseOrderDTO,Integer> colOrderId;
|
@FXML private TableColumn<PurchaseOrderDTO,Long> colOrderId;
|
||||||
@FXML private TableColumn<PurchaseOrderDTO,String> colSupplier;
|
@FXML private TableColumn<PurchaseOrderDTO,String> colSupplier;
|
||||||
@FXML private TableColumn<PurchaseOrderDTO,String> colOrderDate;
|
@FXML private TableColumn<PurchaseOrderDTO,String> colOrderDate;
|
||||||
@FXML private TableColumn<PurchaseOrderDTO,String> colStatus;
|
@FXML private TableColumn<PurchaseOrderDTO,String> colStatus;
|
||||||
@@ -53,17 +58,28 @@ public class PurchaseOrderController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void loadPurchaseOrders() {
|
private void loadPurchaseOrders() {
|
||||||
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
purchaseOrders.setAll(PurchaseOrderDB.getPurchaseOrders());
|
List<PurchaseOrderResponse> responses = PurchaseOrderApi.getInstance().listPurchaseOrders(null);
|
||||||
|
List<PurchaseOrderDTO> dtos = responses.stream()
|
||||||
|
.map(this::mapToPurchaseOrderDTO)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
purchaseOrders.setAll(dtos);
|
||||||
|
tvPurchaseOrders.setItems(filtered);
|
||||||
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
ActivityLogger.getInstance().logException(
|
ActivityLogger.getInstance().logException(
|
||||||
"PurchaseOrderController.loadPurchaseOrders",
|
"PurchaseOrderController.loadPurchaseOrders",
|
||||||
e,
|
e,
|
||||||
"Loading purchase orders for table display");
|
"Loading purchase orders for table display");
|
||||||
e.printStackTrace();
|
|
||||||
new Alert(Alert.AlertType.ERROR,
|
new Alert(Alert.AlertType.ERROR,
|
||||||
"Unable to load purchase orders").showAndWait();
|
"Unable to load purchase orders").showAndWait();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyFilter(String text) {
|
private void applyFilter(String text) {
|
||||||
@@ -93,4 +109,13 @@ public class PurchaseOrderController {
|
|||||||
void btnRefresh() {
|
void btnRefresh() {
|
||||||
loadPurchaseOrders();
|
loadPurchaseOrders();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PurchaseOrderDTO mapToPurchaseOrderDTO(PurchaseOrderResponse response) {
|
||||||
|
return new PurchaseOrderDTO(
|
||||||
|
response.getPurchaseOrderId(),
|
||||||
|
response.getSupplierName(),
|
||||||
|
response.getOrderDate() != null ? response.getOrderDate().toString() : "",
|
||||||
|
response.getOrderStatus()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -22,20 +22,25 @@ import javafx.scene.layout.VBox;
|
|||||||
import javafx.stage.Modality;
|
import javafx.stage.Modality;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.example.petshopdesktop.auth.UserSession;
|
import org.example.petshopdesktop.auth.UserSession;
|
||||||
import org.example.petshopdesktop.database.InventoryDB;
|
import javafx.concurrent.Task;
|
||||||
import org.example.petshopdesktop.database.ProductDB;
|
import org.example.petshopdesktop.api.endpoints.ProductApi;
|
||||||
import org.example.petshopdesktop.database.SaleDB;
|
import org.example.petshopdesktop.api.endpoints.SaleApi;
|
||||||
import org.example.petshopdesktop.models.Inventory;
|
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.Product;
|
||||||
import org.example.petshopdesktop.models.SaleCartItem;
|
import org.example.petshopdesktop.models.SaleCartItem;
|
||||||
import org.example.petshopdesktop.models.SaleLineItem;
|
import org.example.petshopdesktop.models.SaleLineItem;
|
||||||
import org.example.petshopdesktop.util.ActivityLogger;
|
import org.example.petshopdesktop.util.ActivityLogger;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
import java.math.BigDecimal;
|
||||||
import java.text.NumberFormat;
|
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.Locale;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class SaleController {
|
public class SaleController {
|
||||||
|
|
||||||
@@ -124,8 +129,8 @@ public class SaleController {
|
|||||||
private final ObservableList<SaleLineItem> saleItems = FXCollections.observableArrayList();
|
private final ObservableList<SaleLineItem> saleItems = FXCollections.observableArrayList();
|
||||||
private FilteredList<SaleLineItem> filteredSales;
|
private FilteredList<SaleLineItem> filteredSales;
|
||||||
|
|
||||||
private final Map<Integer, Integer> inventoryByProdId = new HashMap<>();
|
|
||||||
private final NumberFormat currency = NumberFormat.getCurrencyInstance(Locale.CANADA);
|
private final NumberFormat currency = NumberFormat.getCurrencyInstance(Locale.CANADA);
|
||||||
|
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
@@ -133,7 +138,6 @@ public class SaleController {
|
|||||||
setupCreateSale();
|
setupCreateSale();
|
||||||
applyRoleMode();
|
applyRoleMode();
|
||||||
|
|
||||||
refreshInventory();
|
|
||||||
refreshSales();
|
refreshSales();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,11 +174,20 @@ public class SaleController {
|
|||||||
updateCartTotal();
|
updateCartTotal();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cbProduct.setItems(ProductDB.getProducts());
|
List<ProductResponse> productResponses = ProductApi.getInstance().listProducts(null);
|
||||||
} catch (SQLException e) {
|
ObservableList<Product> products = FXCollections.observableArrayList();
|
||||||
|
for (ProductResponse pr : productResponses) {
|
||||||
|
products.add(new Product(
|
||||||
|
pr.getProdId().intValue(),
|
||||||
|
pr.getProdName(),
|
||||||
|
pr.getProdPrice().doubleValue(),
|
||||||
|
0,
|
||||||
|
pr.getProdDesc()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
cbProduct.setItems(products);
|
||||||
|
} catch (Exception e) {
|
||||||
ActivityLogger.getInstance().logException("SaleController.setupCreateSale", e, "Loading products");
|
ActivityLogger.getInstance().logException("SaleController.setupCreateSale", e, "Loading products");
|
||||||
} catch (RuntimeException e) {
|
|
||||||
ActivityLogger.getInstance().logException("SaleController.setupCreateSale", e, "Database connection");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,42 +198,61 @@ public class SaleController {
|
|||||||
lblModeNote.setText(isAdmin ? "(View only)" : "(Staff can create sales)");
|
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() {
|
private void refreshSales() {
|
||||||
refreshSales(false);
|
refreshSales(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void refreshSales(boolean showErrorDialog) {
|
private void refreshSales(boolean showErrorDialog) {
|
||||||
try {
|
Task<List<SaleLineItem>> task = new Task<List<SaleLineItem>>() {
|
||||||
saleItems.setAll(SaleDB.getSaleLineItems());
|
@Override
|
||||||
} catch (SQLException e) {
|
protected List<SaleLineItem> call() throws Exception {
|
||||||
ActivityLogger.getInstance().logException("SaleController.refreshSales", e, "Loading sales");
|
List<SaleResponse> sales = SaleApi.getInstance().listSales(0, 1000, null);
|
||||||
|
List<SaleLineItem> 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()) {
|
||||||
|
double unitPrice = item.getUnitPrice() != null ? item.getUnitPrice().doubleValue() : 0.0;
|
||||||
|
double lineTotal = unitPrice * item.getQuantity();
|
||||||
|
lineItems.add(new SaleLineItem(
|
||||||
|
sale.getSaleId().intValue(),
|
||||||
|
saleDate,
|
||||||
|
sale.getEmployeeName(),
|
||||||
|
item.getProductName(),
|
||||||
|
item.getQuantity(),
|
||||||
|
unitPrice,
|
||||||
|
lineTotal,
|
||||||
|
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", (Exception) e, "Loading sales");
|
||||||
if (showErrorDialog) {
|
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
|
@FXML
|
||||||
void btnRefresh(ActionEvent event) {
|
void btnRefresh(ActionEvent event) {
|
||||||
refreshInventory();
|
|
||||||
refreshSales(true);
|
refreshSales(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,18 +276,6 @@ public class SaleController {
|
|||||||
return;
|
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) {
|
for (SaleCartItem item : cartItems) {
|
||||||
if (item.getProdId() == product.getProdId()) {
|
if (item.getProdId() == product.getProdId()) {
|
||||||
item.setQuantity(item.getQuantity() + requestedQty);
|
item.setQuantity(item.getQuantity() + requestedQty);
|
||||||
@@ -291,9 +311,9 @@ public class SaleController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Integer employeeId = UserSession.getInstance().getEmployeeId();
|
Long storeId = UserSession.getInstance().getStoreId();
|
||||||
if (employeeId == null || employeeId <= 0) {
|
if (storeId == null || storeId <= 0) {
|
||||||
showError("Create Sale", "Employee is not set for this account.");
|
showError("Create Sale", "Store is not set for this account.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,20 +329,34 @@ public class SaleController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int saleId = SaleDB.createSale(employeeId, payment, cartItems);
|
SaleRequest request = new SaleRequest();
|
||||||
showInfo("Sale saved", "Sale ID " + saleId + " was created.");
|
request.setStoreId(storeId);
|
||||||
|
request.setPaymentMethod(payment);
|
||||||
|
|
||||||
|
List<SaleItemRequest> itemRequests = new ArrayList<>();
|
||||||
|
for (SaleCartItem cartItem : cartItems) {
|
||||||
|
SaleItemRequest itemRequest = new SaleItemRequest();
|
||||||
|
itemRequest.setProdId((long) cartItem.getProdId());
|
||||||
|
itemRequest.setQuantity(cartItem.getQuantity());
|
||||||
|
itemRequests.add(itemRequest);
|
||||||
|
}
|
||||||
|
request.setItems(itemRequests);
|
||||||
|
|
||||||
|
SaleResponse response = SaleApi.getInstance().createSale(request);
|
||||||
|
showInfo("Sale saved", "Sale ID " + response.getSaleId() + " was created.");
|
||||||
|
|
||||||
cartItems.clear();
|
cartItems.clear();
|
||||||
updateCartTotal();
|
updateCartTotal();
|
||||||
|
|
||||||
refreshInventory();
|
|
||||||
refreshSales(true);
|
refreshSales(true);
|
||||||
} catch (SQLException e) {
|
} catch (Exception e) {
|
||||||
ActivityLogger.getInstance().logException("SaleController.btnSaveSale", e, "Creating sale");
|
ActivityLogger.getInstance().logException("SaleController.btnSaveSale", e, "Creating sale");
|
||||||
showError("Create Sale", e.getMessage() == null ? "Could not save the sale." : e.getMessage());
|
String errorMsg = e.getMessage();
|
||||||
} catch (RuntimeException e) {
|
if (errorMsg != null && errorMsg.contains("Insufficient inventory")) {
|
||||||
ActivityLogger.getInstance().logException("SaleController.btnSaveSale", e, "Database connection");
|
showError("Create Sale", "Insufficient stock for one or more items.");
|
||||||
showError("Create Sale", "Database is not connected.");
|
} else {
|
||||||
|
showError("Create Sale", errorMsg != null ? errorMsg : "Could not save the sale.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,7 +377,6 @@ public class SaleController {
|
|||||||
dialog.setResizable(false);
|
dialog.setResizable(false);
|
||||||
dialog.showAndWait();
|
dialog.showAndWait();
|
||||||
|
|
||||||
refreshInventory();
|
|
||||||
refreshSales(true);
|
refreshSales(true);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ActivityLogger.getInstance().logException("SaleController.openRefundDialog", e, "Opening refund dialog");
|
ActivityLogger.getInstance().logException("SaleController.openRefundDialog", e, "Opening refund dialog");
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package org.example.petshopdesktop.controllers;
|
package org.example.petshopdesktop.controllers;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.collections.transformation.FilteredList;
|
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
@@ -10,12 +10,17 @@ import javafx.scene.Scene;
|
|||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.control.cell.PropertyValueFactory;
|
import javafx.scene.control.cell.PropertyValueFactory;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.example.petshopdesktop.database.ServiceDB;
|
import org.example.petshopdesktop.DTOs.ServiceDTO;
|
||||||
import org.example.petshopdesktop.models.Service;
|
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.controllers.dialogcontrollers.ServiceDialogController;
|
||||||
import org.example.petshopdesktop.util.ActivityLogger;
|
import org.example.petshopdesktop.util.ActivityLogger;
|
||||||
import javafx.stage.Modality;
|
import javafx.stage.Modality;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
public class ServiceController {
|
public class ServiceController {
|
||||||
|
|
||||||
@@ -23,22 +28,23 @@ public class ServiceController {
|
|||||||
@FXML private Button btnDelete;
|
@FXML private Button btnDelete;
|
||||||
@FXML private Button btnEdit;
|
@FXML private Button btnEdit;
|
||||||
|
|
||||||
@FXML private TableColumn<Service, Integer> colServiceId;
|
@FXML private TableColumn<ServiceDTO, Integer> colServiceId;
|
||||||
@FXML private TableColumn<Service, String> colServiceName;
|
@FXML private TableColumn<ServiceDTO, String> colServiceName;
|
||||||
@FXML private TableColumn<Service, String> colServiceDesc;
|
@FXML private TableColumn<ServiceDTO, String> colServiceDesc;
|
||||||
@FXML private TableColumn<Service, Integer> colServiceDuration;
|
@FXML private TableColumn<ServiceDTO, Integer> colServiceDuration;
|
||||||
@FXML private TableColumn<Service, Double> colServicePrice;
|
@FXML private TableColumn<ServiceDTO, Double> colServicePrice;
|
||||||
|
|
||||||
@FXML private TableView<Service> tvServices;
|
@FXML private TableView<ServiceDTO> tvServices;
|
||||||
|
|
||||||
@FXML private TextField txtSearch;
|
@FXML private TextField txtSearch;
|
||||||
|
|
||||||
private final ObservableList<Service> services = FXCollections.observableArrayList();
|
private ObservableList<ServiceDTO> data = FXCollections.observableArrayList();
|
||||||
private FilteredList<Service> filtered;
|
private String mode = null;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
//Enable multiple selection
|
btnEdit.setDisable(true);
|
||||||
|
btnDelete.setDisable(true);
|
||||||
tvServices.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.MULTIPLE);
|
tvServices.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.MULTIPLE);
|
||||||
|
|
||||||
colServiceId.setCellValueFactory(new PropertyValueFactory<>("serviceId"));
|
colServiceId.setCellValueFactory(new PropertyValueFactory<>("serviceId"));
|
||||||
@@ -47,14 +53,19 @@ public class ServiceController {
|
|||||||
colServiceDuration.setCellValueFactory(new PropertyValueFactory<>("serviceDuration"));
|
colServiceDuration.setCellValueFactory(new PropertyValueFactory<>("serviceDuration"));
|
||||||
colServicePrice.setCellValueFactory(new PropertyValueFactory<>("servicePrice"));
|
colServicePrice.setCellValueFactory(new PropertyValueFactory<>("servicePrice"));
|
||||||
|
|
||||||
filtered = new FilteredList<>(services, s -> true);
|
displayServices();
|
||||||
tvServices.setItems(filtered);
|
|
||||||
|
|
||||||
if (txtSearch != null) {
|
tvServices.getSelectionModel().selectedItemProperty().addListener(
|
||||||
txtSearch.textProperty().addListener((obs, o, n) -> applyFilter(n));
|
(observable, oldValue, newValue) -> {
|
||||||
|
btnEdit.setDisable(false);
|
||||||
|
btnDelete.setDisable(false);
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
txtSearch.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
displayFilteredServices(newValue);
|
||||||
|
});
|
||||||
|
|
||||||
//EventListener for DELETE key
|
|
||||||
tvServices.setOnKeyPressed(event -> {
|
tvServices.setOnKeyPressed(event -> {
|
||||||
if (event.getCode() == javafx.scene.input.KeyCode.DELETE) {
|
if (event.getCode() == javafx.scene.input.KeyCode.DELETE) {
|
||||||
if (tvServices.getSelectionModel().getSelectedItem() != null) {
|
if (tvServices.getSelectionModel().getSelectedItem() != null) {
|
||||||
@@ -62,75 +73,82 @@ public class ServiceController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
loadServices();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadServices() {
|
private void displayServices() {
|
||||||
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
services.setAll(ServiceDB.getServices());
|
List<ServiceResponse> services = ServiceApi.getInstance().listServices(null);
|
||||||
|
List<ServiceDTO> serviceDTOs = services.stream()
|
||||||
|
.map(this::mapToServiceDTO)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
data.setAll(serviceDTOs);
|
||||||
|
tvServices.setItems(data);
|
||||||
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||||
ActivityLogger.getInstance().logException(
|
ActivityLogger.getInstance().logException(
|
||||||
"ServiceController.loadServices",
|
"ServiceController.displayServices",
|
||||||
e,
|
e,
|
||||||
"Loading services for table display");
|
"Fetching service data for table display");
|
||||||
showAlert("Database Error", "Unable to load services.");
|
});
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyFilter(String text) {
|
private void displayFilteredServices(String filter) {
|
||||||
if (filtered == null) {
|
if (txtSearch.getText() == null || txtSearch.getText().isEmpty()) {
|
||||||
return;
|
displayServices();
|
||||||
}
|
} else {
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
List<ServiceResponse> services = ServiceApi.getInstance().listServices(filter);
|
||||||
|
List<ServiceDTO> serviceDTOs = services.stream()
|
||||||
|
.map(this::mapToServiceDTO)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
String q = text == null ? "" : text.trim().toLowerCase();
|
Platform.runLater(() -> {
|
||||||
if (q.isEmpty()) {
|
data.setAll(serviceDTOs);
|
||||||
filtered.setPredicate(s -> true);
|
tvServices.setItems(data);
|
||||||
return;
|
});
|
||||||
|
} 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();
|
||||||
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
|
@FXML
|
||||||
void btnAddClicked(ActionEvent event) {
|
void btnAddClicked(ActionEvent event) {
|
||||||
openDialog(null, "Add");
|
mode = "Add";
|
||||||
loadServices();
|
openDialog(null, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
void btnEditClicked(ActionEvent event) {
|
void btnEditClicked(ActionEvent event) {
|
||||||
|
ServiceDTO selected = tvServices.getSelectionModel().getSelectedItem();
|
||||||
|
|
||||||
Service selected = tvServices.getSelectionModel().getSelectedItem();
|
if (selected != null) {
|
||||||
|
mode = "Edit";
|
||||||
if (selected == null) {
|
openDialog(selected, mode);
|
||||||
showAlert("Select Service", "Please select a service to edit.");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
openDialog(selected, "Edit");
|
|
||||||
loadServices();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
void btnDeleteClicked(ActionEvent e) {
|
void btnDeleteClicked(ActionEvent event) {
|
||||||
//get selected services
|
|
||||||
var selectedServices = tvServices.getSelectionModel().getSelectedItems();
|
var selectedServices = tvServices.getSelectionModel().getSelectedItems();
|
||||||
if (selectedServices.isEmpty()) return;
|
if (selectedServices.isEmpty()) return;
|
||||||
|
|
||||||
//ask user to confirm
|
|
||||||
Alert question = new Alert(Alert.AlertType.CONFIRMATION);
|
Alert question = new Alert(Alert.AlertType.CONFIRMATION);
|
||||||
question.setHeaderText("Please confirm delete");
|
question.setHeaderText("Please confirm delete");
|
||||||
String message = selectedServices.size() == 1
|
String message = selectedServices.size() == 1
|
||||||
@@ -138,82 +156,78 @@ public class ServiceController {
|
|||||||
: "Are you sure you want to delete " + selectedServices.size() + " services?";
|
: "Are you sure you want to delete " + selectedServices.size() + " services?";
|
||||||
question.setContentText(message);
|
question.setContentText(message);
|
||||||
question.getDialogPane().lookupButton(ButtonType.OK).requestFocus();
|
question.getDialogPane().lookupButton(ButtonType.OK).requestFocus();
|
||||||
java.util.Optional<ButtonType> result = question.showAndWait();
|
Optional<ButtonType> result = question.showAndWait();
|
||||||
|
|
||||||
//if confirmed, start deletion
|
|
||||||
if (result.isPresent() && result.get() == ButtonType.OK) {
|
if (result.isPresent() && result.get() == ButtonType.OK) {
|
||||||
int successCount = 0;
|
List<Long> ids = selectedServices.stream()
|
||||||
int failCount = 0;
|
.map(s -> (long) s.getServiceId())
|
||||||
StringBuilder errors = new StringBuilder();
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
for (Service service : selectedServices) {
|
|
||||||
try {
|
try {
|
||||||
ServiceDB.deleteService(service.getServiceId());
|
ServiceApi.getInstance().deleteServices(ids);
|
||||||
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) {
|
|
||||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||||
alert.setHeaderText("Database Operation Confirmed");
|
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();
|
alert.showAndWait();
|
||||||
}
|
}
|
||||||
|
|
||||||
//refresh display
|
displayServices();
|
||||||
loadServices();
|
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 {
|
try {
|
||||||
FXMLLoader loader = new FXMLLoader(
|
scene = new Scene(fxmlLoader.load());
|
||||||
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();
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ActivityLogger.getInstance().logException(
|
ActivityLogger.getInstance().logException(
|
||||||
"ServiceController.openDialog",
|
"ServiceController.openDialog",
|
||||||
e,
|
e,
|
||||||
"Opening service dialog in " + mode + " mode");
|
String.format("Loading service dialog view in %s mode", mode));
|
||||||
e.printStackTrace();
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
ServiceDialogController dialogController = fxmlLoader.getController();
|
||||||
private void showAlert(String title, String msg) {
|
dialogController.setMode(mode);
|
||||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
|
||||||
alert.setTitle(title);
|
if (mode.equals("Edit")) {
|
||||||
alert.setHeaderText(null);
|
dialogController.setService(service);
|
||||||
alert.setContentText(msg);
|
}
|
||||||
alert.showAndWait();
|
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 ServiceDTO mapToServiceDTO(ServiceResponse response) {
|
||||||
|
return new ServiceDTO(
|
||||||
|
response.getServiceId().intValue(),
|
||||||
|
response.getServiceName(),
|
||||||
|
response.getServiceDesc(),
|
||||||
|
response.getServiceDuration() != null ? response.getServiceDuration() : 0,
|
||||||
|
response.getServicePrice().doubleValue()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.example.petshopdesktop.controllers;
|
package org.example.petshopdesktop.controllers;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.collections.transformation.FilteredList;
|
import javafx.collections.transformation.FilteredList;
|
||||||
@@ -15,12 +16,16 @@ import javafx.scene.control.TextField;
|
|||||||
import javafx.scene.control.cell.PropertyValueFactory;
|
import javafx.scene.control.cell.PropertyValueFactory;
|
||||||
import javafx.stage.Modality;
|
import javafx.stage.Modality;
|
||||||
import javafx.stage.Stage;
|
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.auth.UserSession;
|
||||||
import org.example.petshopdesktop.database.UserDB;
|
|
||||||
import org.example.petshopdesktop.models.StaffAccount;
|
import org.example.petshopdesktop.models.StaffAccount;
|
||||||
import org.example.petshopdesktop.util.ActivityLogger;
|
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 {
|
public class StaffAccountsController {
|
||||||
|
|
||||||
@@ -107,15 +112,54 @@ public class StaffAccountsController {
|
|||||||
|
|
||||||
private void refresh() {
|
private void refresh() {
|
||||||
lblError.setText("");
|
lblError.setText("");
|
||||||
|
tvStaff.setDisable(true);
|
||||||
|
|
||||||
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
staffAccounts.setAll(UserDB.getStaffAccounts());
|
List<UserResponse> users = UserApi.getInstance().listUsers(null);
|
||||||
} catch (SQLException e) {
|
List<StaffAccount> 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");
|
ActivityLogger.getInstance().logException("StaffAccountsController.refresh", e, "Loading staff accounts");
|
||||||
|
Platform.runLater(() -> {
|
||||||
lblError.setText("Could not load staff accounts.");
|
lblError.setText("Could not load staff accounts.");
|
||||||
} catch (RuntimeException e) {
|
tvStaff.setDisable(false);
|
||||||
ActivityLogger.getInstance().logException("StaffAccountsController.refresh", e, "Database connection");
|
});
|
||||||
lblError.setText("Database is not connected.");
|
|
||||||
}
|
}
|
||||||
|
}).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 = user.getEmail() != null ? user.getEmail() : "";
|
||||||
|
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) {
|
private void applyFilter(String text) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.example.petshopdesktop.controllers;
|
package org.example.petshopdesktop.controllers;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
@@ -10,15 +11,16 @@ import javafx.scene.control.*;
|
|||||||
import javafx.scene.control.cell.PropertyValueFactory;
|
import javafx.scene.control.cell.PropertyValueFactory;
|
||||||
import javafx.stage.Modality;
|
import javafx.stage.Modality;
|
||||||
import javafx.stage.Stage;
|
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.controllers.dialogcontrollers.SupplierDialogController;
|
||||||
import org.example.petshopdesktop.database.SupplierDB;
|
|
||||||
import org.example.petshopdesktop.models.Supplier;
|
import org.example.petshopdesktop.models.Supplier;
|
||||||
import org.example.petshopdesktop.util.ActivityLogger;
|
import org.example.petshopdesktop.util.ActivityLogger;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.sql.SQLException;
|
import java.util.List;
|
||||||
import java.sql.SQLIntegrityConstraintViolationException;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The controller for any operations in the supplier view
|
* The controller for any operations in the supplier view
|
||||||
@@ -105,19 +107,27 @@ public class SupplierController {
|
|||||||
* Display the suppliers to table view
|
* Display the suppliers to table view
|
||||||
*/
|
*/
|
||||||
private void displaySupplier(){
|
private void displaySupplier(){
|
||||||
data.clear();
|
new Thread(() -> {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
data = SupplierDB.getSuppliers();
|
List<SupplierResponse> suppliers = SupplierApi.getInstance().listSuppliers(null);
|
||||||
} catch (SQLException e) {
|
List<Supplier> 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(
|
ActivityLogger.getInstance().logException(
|
||||||
"SupplierController.displaySupplier",
|
"SupplierController.displaySupplier",
|
||||||
e,
|
e,
|
||||||
"Fetching supplier data for table display");
|
"Fetching supplier data for table display");
|
||||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
});
|
||||||
}
|
}
|
||||||
|
}).start();
|
||||||
tvSuppliers.setItems(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -125,22 +135,30 @@ public class SupplierController {
|
|||||||
* @param filter word to filter table
|
* @param filter word to filter table
|
||||||
*/
|
*/
|
||||||
private void displayFilteredSupplier(String filter){
|
private void displayFilteredSupplier(String filter){
|
||||||
data.clear();
|
|
||||||
try{
|
|
||||||
if (txtSearch.getText() == null || txtSearch.getText().isEmpty()){
|
if (txtSearch.getText() == null || txtSearch.getText().isEmpty()){
|
||||||
displaySupplier(); //If search bar is empty just display everything
|
displaySupplier();
|
||||||
}
|
} else {
|
||||||
else{
|
new Thread(() -> {
|
||||||
//Filter the using the keyword
|
try {
|
||||||
data = SupplierDB.getFilteredSuppliers(filter);
|
List<SupplierResponse> suppliers = SupplierApi.getInstance().listSuppliers(filter);
|
||||||
|
List<Supplier> supplierList = suppliers.stream()
|
||||||
|
.map(this::mapToSupplier)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
data.setAll(supplierList);
|
||||||
tvSuppliers.setItems(data);
|
tvSuppliers.setItems(data);
|
||||||
}
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
System.out.println("Error while fetching table data: " + e.getMessage());
|
||||||
ActivityLogger.getInstance().logException(
|
ActivityLogger.getInstance().logException(
|
||||||
"SupplierController.displayFilteredSupplier",
|
"SupplierController.displayFilteredSupplier",
|
||||||
e,
|
e,
|
||||||
"Filtering suppliers with filter: " + filter);
|
"Filtering suppliers with filter: " + filter);
|
||||||
System.out.println("Error while fetching table data: " + e.getMessage());
|
});
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,48 +195,24 @@ public class SupplierController {
|
|||||||
|
|
||||||
//if confirmed, start deletion
|
//if confirmed, start deletion
|
||||||
if (result.isPresent() && result.get() == ButtonType.OK) {
|
if (result.isPresent() && result.get() == ButtonType.OK) {
|
||||||
int successCount = 0;
|
List<Long> ids = selectedSuppliers.stream()
|
||||||
int failCount = 0;
|
.map(s -> (long) s.getSupId())
|
||||||
StringBuilder errors = new StringBuilder();
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
for (Supplier supplier : selectedSuppliers) {
|
|
||||||
try {
|
try {
|
||||||
int numRows = SupplierDB.deleteSupplier(supplier.getSupId());
|
SupplierApi.getInstance().deleteSuppliers(ids);
|
||||||
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) {
|
|
||||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||||
alert.setHeaderText("Database Operation Confirmed");
|
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();
|
alert.showAndWait();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,4 +284,20 @@ public class SupplierController {
|
|||||||
txtSearch.setText("");
|
txtSearch.setText("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Supplier mapToSupplier(SupplierResponse response) {
|
||||||
|
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.getSupId().intValue(),
|
||||||
|
response.getSupCompany(),
|
||||||
|
firstName,
|
||||||
|
lastName,
|
||||||
|
response.getSupEmail(),
|
||||||
|
response.getSupPhone()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.event.EventHandler;
|
import javafx.event.EventHandler;
|
||||||
@@ -12,16 +13,15 @@ import javafx.scene.control.DatePicker;
|
|||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.input.MouseEvent;
|
import javafx.scene.input.MouseEvent;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import javafx.util.StringConverter;
|
import org.example.petshopdesktop.api.dto.adoption.AdoptionRequest;
|
||||||
import org.example.petshopdesktop.database.AdoptionDB;
|
import org.example.petshopdesktop.api.dto.common.DropdownOption;
|
||||||
import org.example.petshopdesktop.database.PetDB;
|
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.Adoption;
|
||||||
import org.example.petshopdesktop.models.Customer;
|
|
||||||
import org.example.petshopdesktop.models.Pet;
|
|
||||||
import org.example.petshopdesktop.util.ActivityLogger;
|
import org.example.petshopdesktop.util.ActivityLogger;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class AdoptionDialogController {
|
public class AdoptionDialogController {
|
||||||
|
|
||||||
@@ -36,10 +36,10 @@ public class AdoptionDialogController {
|
|||||||
private ComboBox<String> cbAdoptionStatus;
|
private ComboBox<String> cbAdoptionStatus;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private ComboBox<Customer> cbCustomer;
|
private ComboBox<DropdownOption> cbCustomer;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private ComboBox<Pet> cbPet;
|
private ComboBox<DropdownOption> cbPet;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private DatePicker dpAdoptionDate;
|
private DatePicker dpAdoptionDate;
|
||||||
@@ -58,52 +58,51 @@ public class AdoptionDialogController {
|
|||||||
"Pending", "Completed", "Cancelled"
|
"Pending", "Completed", "Cancelled"
|
||||||
);
|
);
|
||||||
|
|
||||||
//Loads upon boot
|
|
||||||
@FXML
|
@FXML
|
||||||
void initialize() {
|
void initialize() {
|
||||||
|
|
||||||
//Loads statusList into combo box
|
|
||||||
cbAdoptionStatus.setItems(statusList);
|
cbAdoptionStatus.setItems(statusList);
|
||||||
|
|
||||||
//Pet objects are converted into readable text for combobox (PetID + PetName)
|
new Thread(() -> {
|
||||||
cbPet.setConverter(new StringConverter<Pet>() {
|
|
||||||
@Override
|
|
||||||
public String toString(Pet pet) {
|
|
||||||
return pet == null ? "" : pet.getPetId() + ": " + pet.getPetName();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Not used
|
|
||||||
@Override
|
|
||||||
public Pet fromString(String string) { return null; }
|
|
||||||
});
|
|
||||||
|
|
||||||
//Load pets from DB into pet combobox
|
|
||||||
try {
|
try {
|
||||||
cbPet.setItems(PetDB.getPets());
|
List<DropdownOption> pets = DropdownApi.getInstance().getPets();
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
if (pets != null) {
|
||||||
|
ObservableList<DropdownOption> petsObs = FXCollections.observableArrayList(pets);
|
||||||
|
cbPet.setItems(petsObs);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
catch (SQLException e) {
|
} catch (Exception e) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
ActivityLogger.getInstance().logException(
|
ActivityLogger.getInstance().logException(
|
||||||
"AdoptionDialogController.initialize",
|
"AdoptionDialogController.initialize",
|
||||||
e,
|
e,
|
||||||
"Loading pets for combo box");
|
"Loading pets for combo box");
|
||||||
System.out.println("Error loading pets: " + e.getMessage());
|
System.out.println("Error loading pets: " + e.getMessage());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
}).start();
|
||||||
|
|
||||||
//Load customers from DB into customer combobox
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
cbCustomer.setItems(AdoptionDB.getCustomers());
|
List<DropdownOption> customers = DropdownApi.getInstance().getCustomers();
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
if (customers != null) {
|
||||||
|
ObservableList<DropdownOption> customersObs = FXCollections.observableArrayList(customers);
|
||||||
|
cbCustomer.setItems(customersObs);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
catch (SQLException e) {
|
} catch (Exception e) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
ActivityLogger.getInstance().logException(
|
ActivityLogger.getInstance().logException(
|
||||||
"AdoptionDialogController.initialize",
|
"AdoptionDialogController.initialize",
|
||||||
e,
|
e,
|
||||||
"Loading customers for combo box");
|
"Loading customers for combo box");
|
||||||
System.out.println("Error loading customers: " + e.getMessage());
|
System.out.println("Error loading customers: " + e.getMessage());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
}).start();
|
||||||
|
|
||||||
//Save button handler
|
|
||||||
btnSave.setOnMouseClicked(new EventHandler<MouseEvent>() {
|
btnSave.setOnMouseClicked(new EventHandler<MouseEvent>() {
|
||||||
@Override
|
@Override
|
||||||
public void handle(MouseEvent mouseEvent) {
|
public void handle(MouseEvent mouseEvent) {
|
||||||
@@ -111,7 +110,6 @@ public class AdoptionDialogController {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//Cancel button handler, closes dialog view
|
|
||||||
btnCancel.setOnMouseClicked(new EventHandler<MouseEvent>() {
|
btnCancel.setOnMouseClicked(new EventHandler<MouseEvent>() {
|
||||||
@Override
|
@Override
|
||||||
public void handle(MouseEvent mouseEvent) {
|
public void handle(MouseEvent mouseEvent) {
|
||||||
@@ -120,12 +118,9 @@ public class AdoptionDialogController {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//Handles logic when clicking Save
|
|
||||||
private void buttonSaveClicked(MouseEvent mouseEvent) {
|
private void buttonSaveClicked(MouseEvent mouseEvent) {
|
||||||
int numRow = 0;
|
|
||||||
String errorMsg = "";
|
String errorMsg = "";
|
||||||
|
|
||||||
//Validation: checks if anything is missing
|
|
||||||
if (cbPet.getSelectionModel().getSelectedItem() == null) {
|
if (cbPet.getSelectionModel().getSelectedItem() == null) {
|
||||||
errorMsg += "Pet is required.\n";
|
errorMsg += "Pet is required.\n";
|
||||||
}
|
}
|
||||||
@@ -142,60 +137,41 @@ public class AdoptionDialogController {
|
|||||||
errorMsg += "Status is required.\n";
|
errorMsg += "Status is required.\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
//If no errors, attempt DB operation
|
|
||||||
if (errorMsg.isEmpty()) {
|
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")) {
|
if (mode.equals("Add")) {
|
||||||
try {
|
AdoptionApi.getInstance().createAdoption(request);
|
||||||
numRow = AdoptionDB.insertAdoption(adoption);
|
} else {
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 alert = new Alert(Alert.AlertType.INFORMATION);
|
||||||
alert.setHeaderText("Saved");
|
alert.setHeaderText("Saved");
|
||||||
alert.setContentText(mode + " succeeded");
|
alert.setContentText(mode + " succeeded");
|
||||||
alert.showAndWait();
|
alert.showAndWait();
|
||||||
closeStage(mouseEvent);
|
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();
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
|
||||||
//If there are errors, display them
|
|
||||||
else {
|
|
||||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||||
alert.setHeaderText("Input Error");
|
alert.setHeaderText("Input Error");
|
||||||
alert.setContentText(errorMsg);
|
alert.setContentText(errorMsg);
|
||||||
@@ -203,30 +179,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) {
|
private void closeStage(MouseEvent mouseEvent) {
|
||||||
Node node = (Node) mouseEvent.getSource();
|
Node node = (Node) mouseEvent.getSource();
|
||||||
@@ -234,35 +186,35 @@ public class AdoptionDialogController {
|
|||||||
stage.close();
|
stage.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Edit mode
|
|
||||||
//Inserts data into fields
|
|
||||||
public void displayAdoptionDetails(Adoption adoption) {
|
public void displayAdoptionDetails(Adoption adoption) {
|
||||||
if (adoption != null) {
|
if (adoption != null) {
|
||||||
//Displays adoption ID
|
|
||||||
lblAdoptionId.setText("ID: " + adoption.getAdoptionId());
|
lblAdoptionId.setText("ID: " + adoption.getAdoptionId());
|
||||||
|
|
||||||
//Select pet
|
for (DropdownOption pet : cbPet.getItems()) {
|
||||||
for (Pet pet : cbPet.getItems()) {
|
if (pet.getLabel().equals(adoption.getPetName())) {
|
||||||
if (pet.getPetId() == adoption.getPetId()) {
|
|
||||||
cbPet.getSelectionModel().select(pet);
|
cbPet.getSelectionModel().select(pet);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Select customer
|
for (DropdownOption customer : cbCustomer.getItems()) {
|
||||||
for (Customer customer : cbCustomer.getItems()) {
|
if (customer.getLabel().equals(adoption.getCustomerName())) {
|
||||||
if (customer.getCustomerId() == adoption.getCustomerId()) {
|
|
||||||
cbCustomer.getSelectionModel().select(customer);
|
cbCustomer.getSelectionModel().select(customer);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Select adoption date
|
|
||||||
if (adoption.getAdoptionDate() != null && !adoption.getAdoptionDate().isEmpty()) {
|
if (adoption.getAdoptionDate() != null && !adoption.getAdoptionDate().isEmpty()) {
|
||||||
|
try {
|
||||||
dpAdoptionDate.setValue(LocalDate.parse(adoption.getAdoptionDate()));
|
dpAdoptionDate.setValue(LocalDate.parse(adoption.getAdoptionDate()));
|
||||||
|
} catch (Exception e) {
|
||||||
|
ActivityLogger.getInstance().logException(
|
||||||
|
"AdoptionDialogController.displayAdoptionDetails",
|
||||||
|
e,
|
||||||
|
"Parsing adoption date");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Select adoption status
|
|
||||||
for (String status : cbAdoptionStatus.getItems()) {
|
for (String status : cbAdoptionStatus.getItems()) {
|
||||||
if (status.equals(adoption.getAdoptionStatus())) {
|
if (status.equals(adoption.getAdoptionStatus())) {
|
||||||
cbAdoptionStatus.getSelectionModel().select(status);
|
cbAdoptionStatus.getSelectionModel().select(status);
|
||||||
@@ -272,8 +224,6 @@ public class AdoptionDialogController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Sets dialog mode
|
|
||||||
//Also updates label and adoption ID visibility
|
|
||||||
public void setMode(String mode) {
|
public void setMode(String mode) {
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
lblMode.setText(mode + " Adoption");
|
lblMode.setText(mode + " Adoption");
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
@@ -10,11 +11,16 @@ import javafx.stage.Stage;
|
|||||||
import javafx.scene.control.ListCell;
|
import javafx.scene.control.ListCell;
|
||||||
|
|
||||||
import org.example.petshopdesktop.DTOs.AppointmentDTO;
|
import org.example.petshopdesktop.DTOs.AppointmentDTO;
|
||||||
import org.example.petshopdesktop.database.*;
|
import org.example.petshopdesktop.api.dto.appointment.AppointmentRequest;
|
||||||
import org.example.petshopdesktop.models.*;
|
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 org.example.petshopdesktop.util.ActivityLogger;
|
||||||
|
|
||||||
import java.sql.Time;
|
import java.time.LocalTime;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class AppointmentDialogController {
|
public class AppointmentDialogController {
|
||||||
|
|
||||||
@@ -25,9 +31,9 @@ public class AppointmentDialogController {
|
|||||||
@FXML private Button btnCancel;
|
@FXML private Button btnCancel;
|
||||||
@FXML private Button btnSave;
|
@FXML private Button btnSave;
|
||||||
|
|
||||||
@FXML private ComboBox<Service> cbService;
|
@FXML private ComboBox<DropdownOption> cbService;
|
||||||
@FXML private ComboBox<Customer> cbCustomer;
|
@FXML private ComboBox<DropdownOption> cbCustomer;
|
||||||
@FXML private ComboBox<Pet> cbPet;
|
@FXML private ComboBox<DropdownOption> cbPet;
|
||||||
|
|
||||||
@FXML private ComboBox<Integer> cbHour;
|
@FXML private ComboBox<Integer> cbHour;
|
||||||
@FXML private ComboBox<Integer> cbMinute;
|
@FXML private ComboBox<Integer> cbMinute;
|
||||||
@@ -67,17 +73,33 @@ public class AppointmentDialogController {
|
|||||||
@FXML
|
@FXML
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
|
|
||||||
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
cbService.setItems(ServiceDB.getServices());
|
List<DropdownOption> services = DropdownApi.getInstance().getServices();
|
||||||
cbCustomer.setItems(CustomerDB.getCustomers());
|
List<DropdownOption> customers = DropdownApi.getInstance().getCustomers();
|
||||||
cbPet.setItems(PetDB.getPets());
|
List<DropdownOption> pets = DropdownApi.getInstance().getPets();
|
||||||
|
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
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) {
|
} catch (Exception e) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
ActivityLogger.getInstance().logException(
|
ActivityLogger.getInstance().logException(
|
||||||
"AppointmentDialogController.initialize",
|
"AppointmentDialogController.initialize",
|
||||||
e,
|
e,
|
||||||
"Loading combo box data for services, customers, and pets");
|
"Loading combo box data for services, customers, and pets");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
}).start();
|
||||||
|
|
||||||
cbAppointmentStatus.setItems(statusList);
|
cbAppointmentStatus.setItems(statusList);
|
||||||
|
|
||||||
@@ -88,20 +110,49 @@ public class AppointmentDialogController {
|
|||||||
|
|
||||||
cbMinute.getItems().addAll(0, 15, 30, 45);
|
cbMinute.getItems().addAll(0, 15, 30, 45);
|
||||||
|
|
||||||
// Show pet name
|
// Show dropdown labels
|
||||||
cbPet.setCellFactory(param -> new ListCell<>() {
|
cbService.setCellFactory(param -> new ListCell<>() {
|
||||||
@Override
|
@Override
|
||||||
protected void updateItem(Pet pet, boolean empty) {
|
protected void updateItem(DropdownOption option, boolean empty) {
|
||||||
super.updateItem(pet, empty);
|
super.updateItem(option, empty);
|
||||||
setText(empty || pet == null ? null : pet.getPetName());
|
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<>() {
|
cbPet.setButtonCell(new ListCell<>() {
|
||||||
@Override
|
@Override
|
||||||
protected void updateItem(Pet pet, boolean empty) {
|
protected void updateItem(DropdownOption option, boolean empty) {
|
||||||
super.updateItem(pet, empty);
|
super.updateItem(option, empty);
|
||||||
setText(empty || pet == null ? null : pet.getPetName());
|
setText(empty || option == null ? null : option.getLabel());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -118,26 +169,40 @@ public class AppointmentDialogController {
|
|||||||
selectedAppointment = appt;
|
selectedAppointment = appt;
|
||||||
lblAppointmentId.setText("ID: " + appt.getAppointmentId());
|
lblAppointmentId.setText("ID: " + appt.getAppointmentId());
|
||||||
|
|
||||||
|
try {
|
||||||
dpAppointmentDate.setValue(
|
dpAppointmentDate.setValue(
|
||||||
java.time.LocalDate.parse(appt.getAppointmentDate())
|
java.time.LocalDate.parse(appt.getAppointmentDate())
|
||||||
);
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
ActivityLogger.getInstance().logException(
|
||||||
|
"AppointmentDialogController.displayAppointmentDetails",
|
||||||
|
e,
|
||||||
|
"Parsing appointment date");
|
||||||
|
}
|
||||||
|
|
||||||
cbAppointmentStatus.setValue(appt.getAppointmentStatus());
|
cbAppointmentStatus.setValue(appt.getAppointmentStatus());
|
||||||
|
|
||||||
Time time = Time.valueOf(appt.getAppointmentTime());
|
try {
|
||||||
cbHour.setValue(time.toLocalTime().getHour());
|
LocalTime time = LocalTime.parse(appt.getAppointmentTime());
|
||||||
cbMinute.setValue(time.toLocalTime().getMinute());
|
cbHour.setValue(time.getHour());
|
||||||
|
cbMinute.setValue(time.getMinute());
|
||||||
|
} catch (Exception e) {
|
||||||
|
ActivityLogger.getInstance().logException(
|
||||||
|
"AppointmentDialogController.displayAppointmentDetails",
|
||||||
|
e,
|
||||||
|
"Parsing appointment time");
|
||||||
|
}
|
||||||
|
|
||||||
cbService.getItems().forEach(s -> {
|
cbService.getItems().forEach(s -> {
|
||||||
if (s.getServiceId() == appt.getServiceId()) cbService.setValue(s);
|
if (s.getId() == appt.getServiceId()) cbService.setValue(s);
|
||||||
});
|
});
|
||||||
|
|
||||||
cbCustomer.getItems().forEach(c -> {
|
cbCustomer.getItems().forEach(c -> {
|
||||||
if (c.getCustomerId() == appt.getCustomerId()) cbCustomer.setValue(c);
|
if (c.getId() == appt.getCustomerId()) cbCustomer.setValue(c);
|
||||||
});
|
});
|
||||||
|
|
||||||
cbPet.getItems().forEach(p -> {
|
cbPet.getItems().forEach(p -> {
|
||||||
if (p.getPetId() == appt.getPetId()) cbPet.setValue(p);
|
if (p.getId() == appt.getPetId()) cbPet.setValue(p);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,45 +224,40 @@ public class AppointmentDialogController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Time appointmentTime =
|
LocalTime appointmentTime = LocalTime.of(cbHour.getValue(), cbMinute.getValue());
|
||||||
Time.valueOf(String.format(
|
|
||||||
"%02d:%02d:00",
|
|
||||||
cbHour.getValue(),
|
|
||||||
cbMinute.getValue()
|
|
||||||
));
|
|
||||||
|
|
||||||
Appointment appt = new Appointment(
|
AppointmentRequest request = new AppointmentRequest();
|
||||||
selectedAppointment == null ? 0 : selectedAppointment.getAppointmentId(),
|
request.setPetIds(Collections.singletonList(cbPet.getValue().getId()));
|
||||||
cbService.getValue().getServiceId(),
|
request.setCustomerId(cbCustomer.getValue().getId());
|
||||||
cbCustomer.getValue().getCustomerId(),
|
request.setServiceId(cbService.getValue().getId());
|
||||||
dpAppointmentDate.getValue().toString(),
|
request.setAppointmentDate(dpAppointmentDate.getValue());
|
||||||
appointmentTime.toString(),
|
request.setAppointmentTime(appointmentTime);
|
||||||
cbAppointmentStatus.getValue()
|
request.setAppointmentStatus(cbAppointmentStatus.getValue());
|
||||||
);
|
|
||||||
|
|
||||||
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
if (mode.equals("Add")) {
|
if (mode.equals("Add")) {
|
||||||
int newId = AppointmentDB.insertAppointment(appt);
|
AppointmentApi.getInstance().createAppointment(request);
|
||||||
AppointmentDB.insertAppointmentPet(newId, cbPet.getValue().getPetId());
|
|
||||||
} else {
|
} else {
|
||||||
AppointmentDB.updateAppointment(
|
AppointmentApi.getInstance().updateAppointment(
|
||||||
selectedAppointment.getAppointmentId(),
|
(long) selectedAppointment.getAppointmentId(),
|
||||||
appt,
|
request
|
||||||
cbPet.getValue().getPetId()
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
closeStage(e);
|
Platform.runLater(() -> closeStage(e));
|
||||||
|
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
ActivityLogger.getInstance().logException(
|
ActivityLogger.getInstance().logException(
|
||||||
"AppointmentDialogController.buttonSaveClicked",
|
"AppointmentDialogController.buttonSaveClicked",
|
||||||
ex,
|
ex,
|
||||||
"Saving appointment in " + mode + " mode");
|
"Saving appointment in " + mode + " mode");
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
showError("Error saving appointment");
|
showError("Error saving appointment: " + ex.getMessage());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
||||||
|
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
import javafx.event.EventHandler;
|
import javafx.event.EventHandler;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
@@ -11,14 +13,19 @@ import javafx.scene.control.TextField;
|
|||||||
import javafx.scene.input.MouseEvent;
|
import javafx.scene.input.MouseEvent;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import javafx.util.StringConverter;
|
import javafx.util.StringConverter;
|
||||||
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.models.Inventory;
|
||||||
|
import org.example.petshopdesktop.Validator;
|
||||||
|
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.models.Product;
|
||||||
import org.example.petshopdesktop.util.ActivityLogger;
|
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 {
|
public class InventoryDialogController {
|
||||||
|
|
||||||
@@ -60,12 +67,23 @@ public class InventoryDialogController {
|
|||||||
public Product fromString(String string) { return null; }
|
public Product fromString(String string) { return null; }
|
||||||
});
|
});
|
||||||
|
|
||||||
//Load product list from DB into combobox
|
//Load product list from API into combobox
|
||||||
try {
|
try {
|
||||||
cbProduct.setItems(ProductDB.getProducts());
|
List<ProductResponse> productResponses = ProductApi.getInstance().listProducts(null);
|
||||||
|
if (productResponses != null) {
|
||||||
|
ObservableList<Product> products = FXCollections.observableArrayList();
|
||||||
|
for (ProductResponse pr : productResponses) {
|
||||||
|
products.add(new Product(
|
||||||
|
pr.getProdId().intValue(),
|
||||||
|
pr.getProdName(),
|
||||||
|
pr.getProdPrice().doubleValue(),
|
||||||
|
0,
|
||||||
|
pr.getProdDesc()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
cbProduct.setItems(products);
|
||||||
catch (SQLException e) {
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
ActivityLogger.getInstance().logException(
|
ActivityLogger.getInstance().logException(
|
||||||
"InventoryDialogController.initialize",
|
"InventoryDialogController.initialize",
|
||||||
e,
|
e,
|
||||||
@@ -106,75 +124,43 @@ public class InventoryDialogController {
|
|||||||
|
|
||||||
//Operation only occurs if there are no errors
|
//Operation only occurs if there are no errors
|
||||||
if (errorMsg.isEmpty()) {
|
if (errorMsg.isEmpty()) {
|
||||||
|
try {
|
||||||
//Ensures duplicate entries aren't possible
|
InventoryRequest request = new InventoryRequest();
|
||||||
if (mode.equals("Add")) {
|
|
||||||
Product selectedProduct = cbProduct.getSelectionModel().getSelectedItem();
|
Product selectedProduct = cbProduct.getSelectionModel().getSelectedItem();
|
||||||
|
request.setProdId((long) selectedProduct.getProdId());
|
||||||
|
int quantity;
|
||||||
try {
|
try {
|
||||||
|
quantity = Integer.parseInt(txtQuantity.getText());
|
||||||
if (InventoryDB.productExistsInInventory(selectedProduct.getProdId())) {
|
} catch (NumberFormatException e) {
|
||||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
throw new IllegalArgumentException("Invalid quantity format");
|
||||||
alert.setHeaderText("Duplicate Entry");
|
|
||||||
alert.setContentText("An inventory record for \"" + selectedProduct.getProdName() + "\" already exists.");
|
|
||||||
alert.showAndWait();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
request.setQuantity(quantity);
|
||||||
|
|
||||||
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")) {
|
if (mode.equals("Add")) {
|
||||||
try {
|
InventoryApi.getInstance().createInventory(request);
|
||||||
numRow = InventoryDB.insertInventory(inventory);
|
} else {
|
||||||
} catch (SQLException e) {
|
String[] parts = lblInventoryId.getText().split(": ");
|
||||||
ActivityLogger.getInstance().logException(
|
if (parts.length < 2) {
|
||||||
"InventoryDialogController.buttonSaveClicked",
|
throw new IllegalStateException("Invalid inventory ID format");
|
||||||
e,
|
|
||||||
"Inserting new inventory record");
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
}
|
||||||
|
Long inventoryId = Long.parseLong(parts[1]);
|
||||||
|
InventoryApi.getInstance().updateInventory(inventoryId, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
//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 alert = new Alert(Alert.AlertType.INFORMATION);
|
||||||
alert.setHeaderText("Saved");
|
alert.setHeaderText("Saved");
|
||||||
alert.setContentText(mode + " succeeded");
|
alert.setContentText(mode + " succeeded");
|
||||||
alert.showAndWait();
|
alert.showAndWait();
|
||||||
closeStage(mouseEvent);
|
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 +173,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
|
//Close dialog view
|
||||||
private void closeStage(MouseEvent mouseEvent) {
|
private void closeStage(MouseEvent mouseEvent) {
|
||||||
Node node = (Node) mouseEvent.getSource();
|
Node node = (Node) mouseEvent.getSource();
|
||||||
|
|||||||
@@ -8,14 +8,15 @@ import javafx.scene.Node;
|
|||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.input.MouseEvent;
|
import javafx.scene.input.MouseEvent;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.example.petshopdesktop.DTOs.ProductDTO;
|
|
||||||
import org.example.petshopdesktop.Validator;
|
import org.example.petshopdesktop.Validator;
|
||||||
import org.example.petshopdesktop.database.PetDB;
|
import org.example.petshopdesktop.api.dto.pet.PetRequest;
|
||||||
import org.example.petshopdesktop.models.Category;
|
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.models.Pet;
|
||||||
import org.example.petshopdesktop.util.ActivityLogger;
|
import org.example.petshopdesktop.util.ActivityLogger;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
public class PetDialogController {
|
public class PetDialogController {
|
||||||
|
|
||||||
@@ -77,7 +78,6 @@ public class PetDialogController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void buttonSaveClicked(MouseEvent mouseEvent) {
|
private void buttonSaveClicked(MouseEvent mouseEvent) {
|
||||||
int numRow = 0;
|
|
||||||
String errorMsg = "";
|
String errorMsg = "";
|
||||||
|
|
||||||
//Check validation (input required)
|
//Check validation (input required)
|
||||||
@@ -102,46 +102,34 @@ public class PetDialogController {
|
|||||||
errorMsg += Validator.isNonNegativeInteger(txtPetAge.getText(), "Age");
|
errorMsg += Validator.isNonNegativeInteger(txtPetAge.getText(), "Age");
|
||||||
|
|
||||||
if(errorMsg.isEmpty()){
|
if(errorMsg.isEmpty()){
|
||||||
Pet pet = collectPet();
|
PetRequest request = buildPetRequest();
|
||||||
|
try {
|
||||||
if(mode.equals("Add")) {
|
if(mode.equals("Add")) {
|
||||||
try{
|
PetApi.getInstance().createPet(request);
|
||||||
numRow = PetDB.insertPet(pet);
|
} else {
|
||||||
}
|
String[] parts = lblPetId.getText().split(": ");
|
||||||
catch (SQLException e) {
|
if (parts.length < 2) {
|
||||||
ActivityLogger.getInstance().logException(
|
throw new IllegalStateException("Invalid pet ID format");
|
||||||
"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);
|
|
||||||
}
|
}
|
||||||
|
Long petId = Long.parseLong(parts[1]);
|
||||||
|
PetApi.getInstance().updatePet(petId, 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
|
//tell the user operation was successful
|
||||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||||
alert.setHeaderText("Saved");
|
alert.setHeaderText("Saved");
|
||||||
alert.setContentText(mode + " succeeded");
|
alert.setContentText(mode + " succeeded");
|
||||||
alert.showAndWait();
|
alert.showAndWait();
|
||||||
closeStage(mouseEvent);
|
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{
|
else{
|
||||||
@@ -152,23 +140,27 @@ public class PetDialogController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Pet collectPet() {
|
private PetRequest buildPetRequest() {
|
||||||
int petId =0;
|
PetRequest request = new PetRequest();
|
||||||
Pet pet = null;
|
request.setPetName(txtPetName.getText());
|
||||||
|
request.setPetSpecies(txtPetSpecies.getText());
|
||||||
if(lblPetId.isVisible()){
|
request.setPetBreed(txtPetBreed.getText());
|
||||||
petId = Integer.parseInt(lblPetId.getText().split(": ")[1]);
|
request.setPetStatus(cbPetStatus.getValue());
|
||||||
|
try {
|
||||||
|
request.setPetPrice(new BigDecimal(txtPetPrice.getText()));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new IllegalArgumentException("Invalid price format");
|
||||||
}
|
}
|
||||||
pet = new Pet(
|
|
||||||
petId,
|
int age;
|
||||||
txtPetName.getText(),
|
try {
|
||||||
txtPetSpecies.getText(),
|
age = Integer.parseInt(txtPetAge.getText());
|
||||||
txtPetBreed.getText(),
|
} catch (NumberFormatException e) {
|
||||||
Integer.parseInt(txtPetAge.getText()),
|
throw new IllegalArgumentException("Invalid age format");
|
||||||
cbPetStatus.getValue(),
|
}
|
||||||
Double.parseDouble(txtPetPrice.getText())
|
LocalDate dateOfBirth = LocalDate.now().minusYears(age);
|
||||||
);
|
|
||||||
return pet;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void closeStage(MouseEvent mouseEvent) {
|
private void closeStage(MouseEvent mouseEvent) {
|
||||||
|
|||||||
@@ -10,15 +10,14 @@ import javafx.scene.input.MouseEvent;
|
|||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.example.petshopdesktop.DTOs.ProductDTO;
|
import org.example.petshopdesktop.DTOs.ProductDTO;
|
||||||
import org.example.petshopdesktop.Validator;
|
import org.example.petshopdesktop.Validator;
|
||||||
import org.example.petshopdesktop.database.CategoryDB;
|
import org.example.petshopdesktop.api.dto.common.DropdownOption;
|
||||||
import org.example.petshopdesktop.database.ProductDB;
|
import org.example.petshopdesktop.api.dto.product.ProductRequest;
|
||||||
import org.example.petshopdesktop.models.Category;
|
import org.example.petshopdesktop.api.endpoints.DropdownApi;
|
||||||
import org.example.petshopdesktop.models.Product;
|
import org.example.petshopdesktop.api.endpoints.ProductApi;
|
||||||
import org.example.petshopdesktop.models.Supplier;
|
|
||||||
import org.example.petshopdesktop.util.ActivityLogger;
|
import org.example.petshopdesktop.util.ActivityLogger;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
import java.math.BigDecimal;
|
||||||
import java.util.ArrayList;
|
import java.util.List;
|
||||||
|
|
||||||
public class ProductDialogController {
|
public class ProductDialogController {
|
||||||
|
|
||||||
@@ -29,7 +28,7 @@ public class ProductDialogController {
|
|||||||
private Button btnSave;
|
private Button btnSave;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private ComboBox<Category> cbProdCategory;
|
private ComboBox<DropdownOption> cbProdCategory;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private Label lblMode;
|
private Label lblMode;
|
||||||
@@ -70,16 +69,17 @@ public class ProductDialogController {
|
|||||||
|
|
||||||
//Set up combobox for selecting category
|
//Set up combobox for selecting category
|
||||||
try {
|
try {
|
||||||
//set up combobox
|
List<DropdownOption> categories = DropdownApi.getInstance().getCategories();
|
||||||
ObservableList<Category> categories = FXCollections.observableArrayList(); //empty list
|
if (categories != null) {
|
||||||
categories = CategoryDB.getCategories();
|
ObservableList<DropdownOption> categoriesObs = FXCollections.observableArrayList(categories);
|
||||||
cbProdCategory.setItems(categories);
|
cbProdCategory.setItems(categoriesObs);
|
||||||
} catch (SQLException e) {
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
ActivityLogger.getInstance().logException(
|
ActivityLogger.getInstance().logException(
|
||||||
"ProductDialogController.initialize",
|
"ProductDialogController.initialize",
|
||||||
e,
|
e,
|
||||||
"Loading categories for combo box");
|
"Loading categories for combo box");
|
||||||
throw new RuntimeException(e);
|
System.out.println("Error loading categories: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -108,45 +108,45 @@ public class ProductDialogController {
|
|||||||
//Check Validation (format)
|
//Check Validation (format)
|
||||||
errorMsg += Validator.isNonNegativeDouble(txtProdPrice.getText(), "Product Price");
|
errorMsg += Validator.isNonNegativeDouble(txtProdPrice.getText(), "Product Price");
|
||||||
|
|
||||||
if (errorMsg.isEmpty()) { //no validation errors detected
|
if (errorMsg.isEmpty()) {
|
||||||
Product product = collectProduct(); //get product info
|
|
||||||
if (mode.equals("Add")){ //add mode
|
|
||||||
try {
|
try {
|
||||||
numRow = ProductDB.insertProduct(product);
|
ProductRequest request = new ProductRequest();
|
||||||
} catch (SQLException e) {
|
request.setProdName(txtProdName.getText());
|
||||||
ActivityLogger.getInstance().logException(
|
BigDecimal price;
|
||||||
"ProductDialogController.buttonSaveClicked",
|
|
||||||
e,
|
|
||||||
"Inserting new product record");
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else { //edit
|
|
||||||
try {
|
try {
|
||||||
numRow = ProductDB.updateProduct(product.getProdId(),product);
|
price = new BigDecimal(txtProdPrice.getText());
|
||||||
} catch (SQLException e) {
|
} catch (NumberFormatException e) {
|
||||||
ActivityLogger.getInstance().logException(
|
throw new IllegalArgumentException("Invalid price format");
|
||||||
"ProductDialogController.buttonSaveClicked",
|
|
||||||
e,
|
|
||||||
"Updating product with ID: " + product.getProdId());
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
}
|
||||||
|
request.setProdPrice(price);
|
||||||
|
request.setCategoryId(cbProdCategory.getSelectionModel().getSelectedItem().getId());
|
||||||
|
request.setProdDesc(txtProdDesc.getText());
|
||||||
|
|
||||||
|
if (mode.equals("Add")) {
|
||||||
|
ProductApi.getInstance().createProduct(request);
|
||||||
|
} else {
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
//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 alert = new Alert(Alert.AlertType.INFORMATION);
|
||||||
alert.setHeaderText("Saved");
|
alert.setHeaderText("Saved");
|
||||||
alert.setContentText(mode + " succeeded");
|
alert.setContentText(mode + " succeeded");
|
||||||
alert.showAndWait();
|
alert.showAndWait();
|
||||||
closeStage(mouseEvent);
|
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
|
else{ //Display validation errors
|
||||||
@@ -157,28 +157,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
|
* Display the product data in text fields and combobox
|
||||||
* @param product the product entity containing data to display
|
* @param product the product entity containing data to display
|
||||||
@@ -190,10 +168,10 @@ public class ProductDialogController {
|
|||||||
txtProdDesc.setText(product.getProdDesc());
|
txtProdDesc.setText(product.getProdDesc());
|
||||||
txtProdPrice.setText(product.getProdPrice() + "");
|
txtProdPrice.setText(product.getProdPrice() + "");
|
||||||
|
|
||||||
//get the right combobox selection
|
for (DropdownOption category : cbProdCategory.getItems()) {
|
||||||
for (Category category : cbProdCategory.getItems()) {
|
if(category.getLabel().equals(product.getCategoryName())){
|
||||||
if(category.getCategoryId() == product.getCategoryId()){
|
|
||||||
cbProdCategory.getSelectionModel().select(category);
|
cbProdCategory.getSelectionModel().select(category);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.event.EventHandler;
|
import javafx.event.EventHandler;
|
||||||
@@ -10,16 +11,14 @@ import javafx.scene.input.MouseEvent;
|
|||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.example.petshopdesktop.DTOs.ProductSupplierDTO;
|
import org.example.petshopdesktop.DTOs.ProductSupplierDTO;
|
||||||
import org.example.petshopdesktop.Validator;
|
import org.example.petshopdesktop.Validator;
|
||||||
import org.example.petshopdesktop.database.ProductDB;
|
import org.example.petshopdesktop.api.dto.common.DropdownOption;
|
||||||
import org.example.petshopdesktop.database.ProductSupplierDB;
|
import org.example.petshopdesktop.api.dto.productsupplier.ProductSupplierRequest;
|
||||||
import org.example.petshopdesktop.database.SupplierDB;
|
import org.example.petshopdesktop.api.dto.productsupplier.ProductSupplierResponse;
|
||||||
import org.example.petshopdesktop.models.Product;
|
import org.example.petshopdesktop.api.endpoints.DropdownApi;
|
||||||
import org.example.petshopdesktop.models.ProductSupplier;
|
import org.example.petshopdesktop.api.endpoints.ProductSupplierApi;
|
||||||
import org.example.petshopdesktop.models.Supplier;
|
|
||||||
import org.example.petshopdesktop.util.ActivityLogger;
|
import org.example.petshopdesktop.util.ActivityLogger;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
import java.math.BigDecimal;
|
||||||
import java.sql.SQLIntegrityConstraintViolationException;
|
|
||||||
|
|
||||||
public class ProductSupplierDialogController {
|
public class ProductSupplierDialogController {
|
||||||
|
|
||||||
@@ -30,10 +29,10 @@ public class ProductSupplierDialogController {
|
|||||||
private Button btnSave;
|
private Button btnSave;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private ComboBox<Product> cbProduct;
|
private ComboBox<DropdownOption> cbProduct;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private ComboBox<Supplier> cbSupplier;
|
private ComboBox<DropdownOption> cbSupplier;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private Label lblMode;
|
private Label lblMode;
|
||||||
@@ -67,26 +66,78 @@ public class ProductSupplierDialogController {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//Set up combobox for selecting product and supplier
|
cbSupplier.setButtonCell(new ListCell<DropdownOption>() {
|
||||||
try{
|
@Override
|
||||||
ObservableList<Supplier> suppliers = FXCollections.observableArrayList(); //empty list
|
protected void updateItem(DropdownOption item, boolean empty) {
|
||||||
ObservableList<Product> products = FXCollections.observableArrayList(); //empty list
|
super.updateItem(item, empty);
|
||||||
|
if (empty || item == null) {
|
||||||
//get suppliers and products from DB
|
setText(null);
|
||||||
suppliers = SupplierDB.getSuppliers();
|
} else {
|
||||||
products = ProductDB.getProducts();
|
setText(item.getLabel());
|
||||||
|
|
||||||
//Populate combobox
|
|
||||||
cbSupplier.setItems(suppliers);
|
|
||||||
cbProduct.setItems(products);
|
|
||||||
}
|
}
|
||||||
catch(SQLException e){
|
}
|
||||||
|
});
|
||||||
|
cbSupplier.setCellFactory(lv -> new ListCell<DropdownOption>() {
|
||||||
|
@Override
|
||||||
|
protected void updateItem(DropdownOption item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
if (empty || item == null) {
|
||||||
|
setText(null);
|
||||||
|
} else {
|
||||||
|
setText(item.getLabel());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
cbProduct.setButtonCell(new ListCell<DropdownOption>() {
|
||||||
|
@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<DropdownOption>() {
|
||||||
|
@Override
|
||||||
|
protected void updateItem(DropdownOption item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
if (empty || item == null) {
|
||||||
|
setText(null);
|
||||||
|
} else {
|
||||||
|
setText(item.getLabel());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
var suppliers = DropdownApi.getInstance().getSuppliers();
|
||||||
|
var products = DropdownApi.getInstance().getProducts();
|
||||||
|
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
if (suppliers != null) {
|
||||||
|
cbSupplier.setItems(FXCollections.observableArrayList(suppliers));
|
||||||
|
}
|
||||||
|
if (products != null) {
|
||||||
|
cbProduct.setItems(FXCollections.observableArrayList(products));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
ActivityLogger.getInstance().logException(
|
ActivityLogger.getInstance().logException(
|
||||||
"ProductSupplierDialogController.initialize",
|
"ProductSupplierDialogController.initialize",
|
||||||
e,
|
e,
|
||||||
"Loading suppliers and products for combo boxes");
|
"Loading suppliers and products for combo boxes");
|
||||||
throw new RuntimeException(e);
|
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 +147,8 @@ public class ProductSupplierDialogController {
|
|||||||
* @param mouseEvent click event for save button
|
* @param mouseEvent click event for save button
|
||||||
*/
|
*/
|
||||||
private void buttonSaveClicked(MouseEvent mouseEvent) {
|
private void buttonSaveClicked(MouseEvent mouseEvent) {
|
||||||
int numRows = 0;
|
String errorMsg = "";
|
||||||
String errorMsg = ""; //error message for validation
|
|
||||||
|
|
||||||
//Check Validation (input required)
|
|
||||||
errorMsg += Validator.isPresent(txtCost.getText(), "Cost");
|
errorMsg += Validator.isPresent(txtCost.getText(), "Cost");
|
||||||
if (cbProduct.getSelectionModel().getSelectedItem() == null) {
|
if (cbProduct.getSelectionModel().getSelectedItem() == null) {
|
||||||
errorMsg += "Product is required \n";
|
errorMsg += "Product is required \n";
|
||||||
@@ -108,82 +157,41 @@ public class ProductSupplierDialogController {
|
|||||||
errorMsg += "Supplier is required \n";
|
errorMsg += "Supplier is required \n";
|
||||||
}
|
}
|
||||||
|
|
||||||
//Check validation (length size)
|
|
||||||
errorMsg += Validator.isLessThanVarChars(txtCost.getText(), "Cost", 12);
|
errorMsg += Validator.isLessThanVarChars(txtCost.getText(), "Cost", 12);
|
||||||
|
|
||||||
//Check validation (format)
|
|
||||||
errorMsg += Validator.isNonNegativeDouble(txtCost.getText(), "Cost");
|
errorMsg += Validator.isNonNegativeDouble(txtCost.getText(), "Cost");
|
||||||
|
|
||||||
if(errorMsg.isEmpty()){ //no validation errors
|
if(errorMsg.isEmpty()){
|
||||||
ProductSupplier productSupplier = collectProductSupplier(); //get productSupplier info
|
ProductSupplierRequest request = collectProductSupplierRequest();
|
||||||
if (mode.equals("Add")) { //add mode
|
|
||||||
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
numRows = ProductSupplierDB.insertProductSupplier(productSupplier);
|
if (mode.equals("Add")) {
|
||||||
}
|
ProductSupplierApi.getInstance().createProductSupplier(request);
|
||||||
catch(SQLIntegrityConstraintViolationException e){
|
} else {
|
||||||
ActivityLogger.getInstance().logException(
|
ProductSupplierApi.getInstance().updateProductSupplier((long) selectedProdId, (long) selectedSupId, request);
|
||||||
"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 no rows were affected then there was an error (prompt user of error)
|
Platform.runLater(() -> {
|
||||||
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 alert = new Alert(Alert.AlertType.INFORMATION);
|
||||||
alert.setHeaderText("Saved");
|
alert.setHeaderText("Saved");
|
||||||
alert.setContentText(mode + " succeeded");
|
alert.setContentText(mode + " succeeded");
|
||||||
alert.showAndWait();
|
alert.showAndWait();
|
||||||
closeStage(mouseEvent);
|
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 { //Display validation errors
|
} else {
|
||||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||||
alert.setHeaderText("Input Error");
|
alert.setHeaderText("Input Error");
|
||||||
alert.setContentText(errorMsg);
|
alert.setContentText(errorMsg);
|
||||||
@@ -193,18 +201,18 @@ public class ProductSupplierDialogController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* collect the data for new/updated productSupplier
|
* collect the data for new/updated productSupplier
|
||||||
* @return productSupplier entity with data
|
* @return productSupplier request with data
|
||||||
*/
|
*/
|
||||||
private ProductSupplier collectProductSupplier() {
|
private ProductSupplierRequest collectProductSupplierRequest() {
|
||||||
ProductSupplier productSupplier = null;
|
ProductSupplierRequest request = new ProductSupplierRequest();
|
||||||
|
request.setSupplierId(cbSupplier.getSelectionModel().getSelectedItem().getId());
|
||||||
productSupplier = new ProductSupplier(
|
request.setProductId(cbProduct.getSelectionModel().getSelectedItem().getId());
|
||||||
cbSupplier.getSelectionModel().getSelectedItem().getSupId(),
|
try {
|
||||||
cbProduct.getSelectionModel().getSelectedItem().getProdId(),
|
request.setCost(new BigDecimal(txtCost.getText()));
|
||||||
Double.parseDouble(txtCost.getText())
|
} catch (NumberFormatException e) {
|
||||||
);
|
throw new IllegalArgumentException("Invalid cost format");
|
||||||
|
}
|
||||||
return productSupplier;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -216,20 +224,17 @@ public class ProductSupplierDialogController {
|
|||||||
txtCost.setText(productSupplier.getCost() + "");
|
txtCost.setText(productSupplier.getCost() + "");
|
||||||
}
|
}
|
||||||
|
|
||||||
//Get the right combobox selection (product)
|
for (DropdownOption product : cbProduct.getItems()) {
|
||||||
for (Product product : cbProduct.getItems()) {
|
if(product.getId() == productSupplier.getProdId()){
|
||||||
if(product.getProdId() == productSupplier.getProdId()){
|
|
||||||
cbProduct.getSelectionModel().select(product);
|
cbProduct.getSelectionModel().select(product);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Get the right combobox selection (supplier)
|
for (DropdownOption supplier : cbSupplier.getItems()) {
|
||||||
for (Supplier supplier : cbSupplier.getItems()) {
|
if (supplier.getId() == productSupplier.getSupId()) {
|
||||||
if (supplier.getSupId() == productSupplier.getSupId()) {
|
|
||||||
cbSupplier.getSelectionModel().select(supplier);
|
cbSupplier.getSelectionModel().select(supplier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -7,15 +7,19 @@ import javafx.fxml.FXML;
|
|||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.control.cell.PropertyValueFactory;
|
import javafx.scene.control.cell.PropertyValueFactory;
|
||||||
import javafx.stage.Stage;
|
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.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 org.example.petshopdesktop.util.ActivityLogger;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
import java.math.BigDecimal;
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@@ -31,19 +35,19 @@ public class RefundDialogController {
|
|||||||
private Label lblSaleInfo;
|
private Label lblSaleInfo;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private TableView<SaleDetail.SaleDetailItem> tvOriginalItems;
|
private TableView<SaleItemResponse> tvOriginalItems;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private TableColumn<SaleDetail.SaleDetailItem, String> colOriginalProduct;
|
private TableColumn<SaleItemResponse, String> colOriginalProduct;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private TableColumn<SaleDetail.SaleDetailItem, Integer> colOriginalQuantity;
|
private TableColumn<SaleItemResponse, Integer> colOriginalQuantity;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private TableColumn<SaleDetail.SaleDetailItem, Double> colOriginalUnitPrice;
|
private TableColumn<SaleItemResponse, BigDecimal> colOriginalUnitPrice;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private TableColumn<SaleDetail.SaleDetailItem, Double> colOriginalTotal;
|
private TableColumn<SaleItemResponse, BigDecimal> colOriginalTotal;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private Button btnAddToRefund;
|
private Button btnAddToRefund;
|
||||||
@@ -78,7 +82,7 @@ public class RefundDialogController {
|
|||||||
@FXML
|
@FXML
|
||||||
private Button btnCancel;
|
private Button btnCancel;
|
||||||
|
|
||||||
private SaleDetail currentSale;
|
private SaleResponse currentSale;
|
||||||
private final ObservableList<RefundItem> refundItems = FXCollections.observableArrayList();
|
private final ObservableList<RefundItem> refundItems = FXCollections.observableArrayList();
|
||||||
private final NumberFormat currency = NumberFormat.getCurrencyInstance(Locale.CANADA);
|
private final NumberFormat currency = NumberFormat.getCurrencyInstance(Locale.CANADA);
|
||||||
|
|
||||||
@@ -94,7 +98,7 @@ public class RefundDialogController {
|
|||||||
colOriginalProduct.setCellValueFactory(new PropertyValueFactory<>("productName"));
|
colOriginalProduct.setCellValueFactory(new PropertyValueFactory<>("productName"));
|
||||||
colOriginalQuantity.setCellValueFactory(new PropertyValueFactory<>("quantity"));
|
colOriginalQuantity.setCellValueFactory(new PropertyValueFactory<>("quantity"));
|
||||||
colOriginalUnitPrice.setCellValueFactory(new PropertyValueFactory<>("unitPrice"));
|
colOriginalUnitPrice.setCellValueFactory(new PropertyValueFactory<>("unitPrice"));
|
||||||
colOriginalTotal.setCellValueFactory(new PropertyValueFactory<>("total"));
|
colOriginalTotal.setCellValueFactory(new PropertyValueFactory<>("lineTotal"));
|
||||||
tvOriginalItems.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
|
tvOriginalItems.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
|
||||||
|
|
||||||
colRefundProduct.setCellValueFactory(new PropertyValueFactory<>("productName"));
|
colRefundProduct.setCellValueFactory(new PropertyValueFactory<>("productName"));
|
||||||
@@ -113,21 +117,25 @@ public class RefundDialogController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int saleId;
|
Long saleId;
|
||||||
try {
|
try {
|
||||||
saleId = Integer.parseInt(saleIdText);
|
saleId = Long.parseLong(saleIdText);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
showError("Load Sale", "Invalid transaction ID.");
|
showError("Load Sale", "Invalid transaction ID.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (SaleDB.isRefunded(saleId)) {
|
List<SaleResponse> 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.");
|
showError("Load Sale", "This sale has already been refunded.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
currentSale = SaleDB.getSaleById(saleId);
|
currentSale = SaleApi.getInstance().getSale(saleId);
|
||||||
|
|
||||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
|
||||||
String saleInfo = String.format("Sale Date: %s | Employee: %s | Original Total: %s | Payment: %s",
|
String saleInfo = String.format("Sale Date: %s | Employee: %s | Original Total: %s | Payment: %s",
|
||||||
@@ -137,13 +145,13 @@ public class RefundDialogController {
|
|||||||
currentSale.getPaymentMethod());
|
currentSale.getPaymentMethod());
|
||||||
lblSaleInfo.setText(saleInfo);
|
lblSaleInfo.setText(saleInfo);
|
||||||
|
|
||||||
tvOriginalItems.setItems(currentSale.getItems());
|
tvOriginalItems.setItems(FXCollections.observableArrayList(currentSale.getItems()));
|
||||||
cbPaymentMethod.getSelectionModel().select(currentSale.getPaymentMethod());
|
cbPaymentMethod.getSelectionModel().select(currentSale.getPaymentMethod());
|
||||||
|
|
||||||
refundItems.clear();
|
refundItems.clear();
|
||||||
updateRefundTotal();
|
updateRefundTotal();
|
||||||
|
|
||||||
} catch (SQLException e) {
|
} catch (Exception e) {
|
||||||
ActivityLogger.getInstance().logException("RefundDialogController.btnLoadSaleClicked", e, "Loading sale");
|
ActivityLogger.getInstance().logException("RefundDialogController.btnLoadSaleClicked", e, "Loading sale");
|
||||||
showError("Load Sale", e.getMessage() != null ? e.getMessage() : "Could not load sale.");
|
showError("Load Sale", e.getMessage() != null ? e.getMessage() : "Could not load sale.");
|
||||||
}
|
}
|
||||||
@@ -156,14 +164,14 @@ public class RefundDialogController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SaleDetail.SaleDetailItem selected = tvOriginalItems.getSelectionModel().getSelectedItem();
|
SaleItemResponse selected = tvOriginalItems.getSelectionModel().getSelectedItem();
|
||||||
if (selected == null) {
|
if (selected == null) {
|
||||||
showError("Add to Refund", "Select an item from the original sale.");
|
showError("Add to Refund", "Select an item from the original sale.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int alreadyRefunded = refundItems.stream()
|
int alreadyRefunded = refundItems.stream()
|
||||||
.filter(r -> r.getProdId() == selected.getProdId())
|
.filter(r -> r.getProdId() == selected.getSaleItemId().intValue())
|
||||||
.mapToInt(RefundItem::getQuantity)
|
.mapToInt(RefundItem::getQuantity)
|
||||||
.sum();
|
.sum();
|
||||||
|
|
||||||
@@ -192,10 +200,10 @@ public class RefundDialogController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
refundItems.add(new RefundItem(
|
refundItems.add(new RefundItem(
|
||||||
selected.getProdId(),
|
selected.getSaleItemId().intValue(),
|
||||||
selected.getProductName(),
|
selected.getProductName(),
|
||||||
quantity,
|
quantity,
|
||||||
selected.getUnitPrice()
|
selected.getUnitPrice().doubleValue()
|
||||||
));
|
));
|
||||||
updateRefundTotal();
|
updateRefundTotal();
|
||||||
|
|
||||||
@@ -226,9 +234,9 @@ public class RefundDialogController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Integer employeeId = UserSession.getInstance().getEmployeeId();
|
Long storeId = UserSession.getInstance().getStoreId();
|
||||||
if (employeeId == null || employeeId <= 0) {
|
if (storeId == null || storeId <= 0) {
|
||||||
showError("Process Refund", "Employee is not set for this account.");
|
showError("Process Refund", "Store is not set for this account.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,22 +257,32 @@ public class RefundDialogController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ObservableList<SaleCartItem> cartItems = FXCollections.observableArrayList();
|
SaleRequest request = new SaleRequest();
|
||||||
for (RefundItem item : refundItems) {
|
request.setStoreId(storeId);
|
||||||
cartItems.add(new SaleCartItem(item.getProdId(), item.getProductName(), item.getQuantity(), item.getUnitPrice()));
|
request.setPaymentMethod(payment);
|
||||||
}
|
request.setIsRefund(true);
|
||||||
|
request.setOriginalSaleId(currentSale.getSaleId());
|
||||||
|
|
||||||
int refundId = SaleDB.createRefund(currentSale.getSaleId(), employeeId, payment, cartItems);
|
List<SaleItemRequest> items = new ArrayList<>();
|
||||||
|
for (RefundItem item : refundItems) {
|
||||||
|
SaleItemRequest saleItem = new SaleItemRequest();
|
||||||
|
saleItem.setProdId((long) item.getProdId());
|
||||||
|
saleItem.setQuantity(-item.getQuantity());
|
||||||
|
items.add(saleItem);
|
||||||
|
}
|
||||||
|
request.setItems(items);
|
||||||
|
|
||||||
|
SaleResponse refundResponse = SaleApi.getInstance().createSale(request);
|
||||||
|
|
||||||
Alert success = new Alert(Alert.AlertType.INFORMATION);
|
Alert success = new Alert(Alert.AlertType.INFORMATION);
|
||||||
success.setTitle("Refund Processed");
|
success.setTitle("Refund Processed");
|
||||||
success.setHeaderText(null);
|
success.setHeaderText(null);
|
||||||
success.setContentText("Refund ID " + refundId + " was created successfully.");
|
success.setContentText("Refund ID " + refundResponse.getSaleId() + " was created successfully.");
|
||||||
success.showAndWait();
|
success.showAndWait();
|
||||||
|
|
||||||
closeDialog();
|
closeDialog();
|
||||||
|
|
||||||
} catch (SQLException e) {
|
} catch (Exception e) {
|
||||||
ActivityLogger.getInstance().logException("RefundDialogController.btnProcessRefundClicked", e, "Processing refund");
|
ActivityLogger.getInstance().logException("RefundDialogController.btnProcessRefundClicked", e, "Processing refund");
|
||||||
showError("Process Refund", e.getMessage() != null ? e.getMessage() : "Could not process refund.");
|
showError("Process Refund", e.getMessage() != null ? e.getMessage() : "Could not process refund.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.control.Alert;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.control.ComboBox;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
import javafx.scene.input.MouseEvent;
|
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.example.petshopdesktop.database.ServiceDB;
|
import org.example.petshopdesktop.DTOs.ServiceDTO;
|
||||||
import org.example.petshopdesktop.models.Service;
|
import org.example.petshopdesktop.api.dto.service.ServiceRequest;
|
||||||
|
import org.example.petshopdesktop.api.endpoints.ServiceApi;
|
||||||
import org.example.petshopdesktop.util.ActivityLogger;
|
import org.example.petshopdesktop.util.ActivityLogger;
|
||||||
import javafx.scene.control.Alert;
|
|
||||||
import javafx.scene.control.ComboBox;
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
|
||||||
public class ServiceDialogController {
|
public class ServiceDialogController {
|
||||||
@@ -45,7 +46,7 @@ public class ServiceDialogController {
|
|||||||
private ComboBox<Integer> cbMinutes;
|
private ComboBox<Integer> cbMinutes;
|
||||||
|
|
||||||
private String mode;
|
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;
|
this.selectedService = service;
|
||||||
|
|
||||||
lblServiceId.setText("ID: " + service.getServiceId());
|
lblServiceId.setText("ID: " + service.getServiceId());
|
||||||
@@ -114,22 +115,20 @@ public class ServiceDialogController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int duration = (hours * 60) + minutes;
|
|
||||||
|
|
||||||
Service service = new Service(
|
|
||||||
selectedService == null ? 0 : selectedService.getServiceId(),
|
|
||||||
name,
|
|
||||||
desc,
|
|
||||||
duration,
|
|
||||||
price
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
int durationMinutes = (hours * 60) + minutes;
|
||||||
|
|
||||||
|
ServiceRequest request = new ServiceRequest();
|
||||||
|
request.setServiceName(name);
|
||||||
|
request.setServiceDesc(desc);
|
||||||
|
request.setServicePrice(BigDecimal.valueOf(price));
|
||||||
|
request.setServiceDuration(durationMinutes);
|
||||||
|
|
||||||
if (mode.equals("Add")) {
|
if (mode.equals("Add")) {
|
||||||
ServiceDB.insertService(service);
|
ServiceApi.getInstance().createService(request);
|
||||||
} else {
|
} else {
|
||||||
ServiceDB.updateService(selectedService.getServiceId(), service);
|
Long serviceId = (long) selectedService.getServiceId();
|
||||||
|
ServiceApi.getInstance().updateService(serviceId, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
close();
|
close();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
package org.example.petshopdesktop.controllers.dialogcontrollers;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.control.Alert;
|
import javafx.scene.control.Alert;
|
||||||
@@ -8,11 +9,10 @@ import javafx.scene.control.Label;
|
|||||||
import javafx.scene.control.PasswordField;
|
import javafx.scene.control.PasswordField;
|
||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
import javafx.stage.Stage;
|
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 org.example.petshopdesktop.util.ActivityLogger;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
public class StaffRegisterDialogController {
|
public class StaffRegisterDialogController {
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
@@ -49,7 +49,6 @@ public class StaffRegisterDialogController {
|
|||||||
String firstName = value(txtFirstName);
|
String firstName = value(txtFirstName);
|
||||||
String lastName = value(txtLastName);
|
String lastName = value(txtLastName);
|
||||||
String email = value(txtEmail);
|
String email = value(txtEmail);
|
||||||
String phone = value(txtPhone);
|
|
||||||
String username = value(txtUsername);
|
String username = value(txtUsername);
|
||||||
String password = txtPassword.getText() == null ? "" : txtPassword.getText();
|
String password = txtPassword.getText() == null ? "" : txtPassword.getText();
|
||||||
String confirm = txtPasswordConfirm.getText() == null ? "" : txtPasswordConfirm.getText();
|
String confirm = txtPasswordConfirm.getText() == null ? "" : txtPasswordConfirm.getText();
|
||||||
@@ -62,10 +61,6 @@ public class StaffRegisterDialogController {
|
|||||||
lblError.setText("Email is required.");
|
lblError.setText("Email is required.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (phone.isBlank()) {
|
|
||||||
lblError.setText("Phone is required.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (username.isBlank()) {
|
if (username.isBlank()) {
|
||||||
lblError.setText("Username is required.");
|
lblError.setText("Username is required.");
|
||||||
return;
|
return;
|
||||||
@@ -79,26 +74,41 @@ public class StaffRegisterDialogController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
btnCreate.setDisable(true);
|
||||||
|
|
||||||
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
UserDB.createStaffAccount(firstName, lastName, email, phone, username, password);
|
UserRequest request = new UserRequest();
|
||||||
|
request.setUsername(username);
|
||||||
|
request.setPassword(password);
|
||||||
|
request.setFullName(firstName + " " + lastName);
|
||||||
|
request.setEmail(email);
|
||||||
|
request.setRole("STAFF");
|
||||||
|
request.setActive(true);
|
||||||
|
|
||||||
|
UserApi.getInstance().createUser(request);
|
||||||
|
|
||||||
|
Platform.runLater(() -> {
|
||||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||||
alert.setTitle("Staff Account");
|
alert.setTitle("Staff Account");
|
||||||
alert.setHeaderText(null);
|
alert.setHeaderText(null);
|
||||||
alert.setContentText("Staff account created. You can log in now.");
|
alert.setContentText("Staff account created. You can log in now.");
|
||||||
alert.showAndWait();
|
alert.showAndWait();
|
||||||
close();
|
close();
|
||||||
} catch (SQLException e) {
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
ActivityLogger.getInstance().logException("StaffRegisterDialogController.btnCreateClicked", e, "Creating staff account");
|
ActivityLogger.getInstance().logException("StaffRegisterDialogController.btnCreateClicked", e, "Creating staff account");
|
||||||
String msg = e.getMessage() == null ? "Could not create staff account." : e.getMessage();
|
String msg = e.getMessage() == null ? "Could not create staff account." : e.getMessage();
|
||||||
|
Platform.runLater(() -> {
|
||||||
if (msg.toLowerCase().contains("duplicate") || msg.toLowerCase().contains("unique")) {
|
if (msg.toLowerCase().contains("duplicate") || msg.toLowerCase().contains("unique")) {
|
||||||
lblError.setText("Username already exists.");
|
lblError.setText("Username already exists.");
|
||||||
} else {
|
} else {
|
||||||
lblError.setText(msg);
|
lblError.setText(msg);
|
||||||
}
|
}
|
||||||
} catch (RuntimeException e) {
|
btnCreate.setDisable(false);
|
||||||
ActivityLogger.getInstance().logException("StaffRegisterDialogController.btnCreateClicked", e, "Database connection");
|
});
|
||||||
lblError.setText("Database is not connected.");
|
|
||||||
}
|
}
|
||||||
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ import javafx.scene.control.TextField;
|
|||||||
import javafx.scene.input.MouseEvent;
|
import javafx.scene.input.MouseEvent;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.example.petshopdesktop.Validator;
|
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.models.Supplier;
|
||||||
import org.example.petshopdesktop.util.ActivityLogger;
|
import org.example.petshopdesktop.util.ActivityLogger;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
public class SupplierDialogController {
|
public class SupplierDialogController {
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
@@ -74,7 +74,6 @@ public class SupplierDialogController {
|
|||||||
* @param mouseEvent click event for save button
|
* @param mouseEvent click event for save button
|
||||||
*/
|
*/
|
||||||
private void buttonSaveClicked(MouseEvent mouseEvent) {
|
private void buttonSaveClicked(MouseEvent mouseEvent) {
|
||||||
int numRow = 0; //how many rows affected
|
|
||||||
String errorMsg = ""; //error message for validation
|
String errorMsg = ""; //error message for validation
|
||||||
|
|
||||||
//Check validation (input required)
|
//Check validation (input required)
|
||||||
@@ -95,44 +94,33 @@ public class SupplierDialogController {
|
|||||||
errorMsg += Validator.isValidPhoneNumber(txtPhone.getText(), "Phone Number");
|
errorMsg += Validator.isValidPhoneNumber(txtPhone.getText(), "Phone Number");
|
||||||
|
|
||||||
if(errorMsg.isEmpty()){ //no validation errors detected
|
if(errorMsg.isEmpty()){ //no validation errors detected
|
||||||
Supplier supplier = collectSupplier(); //get supplier info
|
SupplierRequest request = createSupplierRequest();
|
||||||
if (mode.equals("Add")) { //add mode
|
|
||||||
try {
|
try {
|
||||||
numRow = SupplierDB.insertSupplier(supplier);
|
if (mode.equals("Add")) {
|
||||||
} catch (SQLException e) {
|
SupplierApi.getInstance().createSupplier(request);
|
||||||
ActivityLogger.getInstance().logException(
|
} else {
|
||||||
"SupplierDialogController.buttonSaveClicked",
|
String[] parts = lblSupId.getText().split(": ");
|
||||||
e,
|
if (parts.length < 2) {
|
||||||
"Inserting new supplier record");
|
throw new IllegalStateException("Invalid supplier ID format");
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
Long supplierId = Long.parseLong(parts[1]);
|
||||||
|
SupplierApi.getInstance().updateSupplier(supplierId, 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 alert = new Alert(Alert.AlertType.INFORMATION);
|
||||||
alert.setHeaderText("Saved");
|
alert.setHeaderText("Saved");
|
||||||
alert.setContentText(mode + " succeeded");
|
alert.setContentText(mode + " succeeded");
|
||||||
alert.showAndWait();
|
alert.showAndWait();
|
||||||
closeStage(mouseEvent);
|
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
|
else{ //Display validation errors
|
||||||
@@ -154,26 +142,17 @@ public class SupplierDialogController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collect the supplier info
|
* Create a supplier request from the form inputs
|
||||||
* @return supplier info with the id or the new supplier
|
* @return supplier request for API call
|
||||||
*/
|
*/
|
||||||
private Supplier collectSupplier(){
|
private SupplierRequest createSupplierRequest(){
|
||||||
int supId = 0;
|
SupplierRequest request = new SupplierRequest();
|
||||||
Supplier supplier = null;
|
request.setSupCompany(txtCompanyName.getText());
|
||||||
|
request.setSupContactFirstName(txtContactFirstName.getText());
|
||||||
if(lblSupId.isVisible()){ //Edit mode
|
request.setSupContactLastName(txtContactLastName.getText());
|
||||||
//get supplier id from lblId (split the string so we only get the int)
|
request.setSupEmail(txtEmail.getText());
|
||||||
supId = Integer.parseInt(lblSupId.getText().split(": ")[1]);
|
request.setSupPhone(txtPhone.getText());
|
||||||
}
|
return request;
|
||||||
supplier = new Supplier(
|
|
||||||
supId,
|
|
||||||
txtCompanyName.getText(),
|
|
||||||
txtContactFirstName.getText(),
|
|
||||||
txtContactLastName.getText(),
|
|
||||||
txtEmail.getText(),
|
|
||||||
txtPhone.getText()
|
|
||||||
);
|
|
||||||
return supplier;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,165 +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<Adoption> getAdoptions() throws SQLException {
|
|
||||||
ObservableList<Adoption> 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<Adoption> getFilteredAdoptions(String filter) throws SQLException {
|
|
||||||
ObservableList<Adoption> 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<Customer> getCustomers() throws SQLException {
|
|
||||||
ObservableList<Customer> 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")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<AppointmentDTO> getAppointmentDTOs()
|
|
||||||
throws SQLException {
|
|
||||||
|
|
||||||
ObservableList<AppointmentDTO> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<Category> getCategories() throws SQLException{
|
|
||||||
//Connect to the database
|
|
||||||
ObservableList<Category> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<Customer> getCustomers()
|
|
||||||
throws SQLException {
|
|
||||||
|
|
||||||
ObservableList<Customer> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,158 +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<Inventory> getInventory() throws SQLException {
|
|
||||||
ObservableList<Inventory> 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<Inventory> getFilteredInventory(String filter) throws SQLException {
|
|
||||||
ObservableList<Inventory> 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"),
|
|
||||||
rs.getInt("quantity")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<Pet> getPets() throws SQLException {
|
|
||||||
//Connect to the database
|
|
||||||
ObservableList<Pet> 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<Pet> getFilteredPets(String filter) throws SQLException {
|
|
||||||
//Connect to the database
|
|
||||||
ObservableList<Pet> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<Product> getProducts() throws SQLException{
|
|
||||||
//Connect to the database
|
|
||||||
ObservableList<Product> 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<ProductDTO> getProductDTO() throws SQLException{
|
|
||||||
//Connect to the database
|
|
||||||
ObservableList<ProductDTO> 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<ProductDTO> getFilteredProductDTOs(String filter) throws SQLException {
|
|
||||||
//Connect to the database
|
|
||||||
ObservableList<ProductDTO> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<ProductSupplierDTO> getProductSupplierDTO() throws SQLException{
|
|
||||||
//Connect to the database
|
|
||||||
ObservableList<ProductSupplierDTO> 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<ProductSupplierDTO> getFilteredProductSupplierDTO (String filter) throws SQLException {
|
|
||||||
//connect to the database
|
|
||||||
ObservableList<ProductSupplierDTO> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<PurchaseOrderDTO> getPurchaseOrders()
|
|
||||||
throws SQLException {
|
|
||||||
|
|
||||||
ObservableList<PurchaseOrderDTO> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<SaleDTO> getSales() throws SQLException {
|
|
||||||
ObservableList<SaleDTO> 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<SaleDTO> getFilteredSales(String filter) throws SQLException {
|
|
||||||
ObservableList<SaleDTO> 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<SaleLineItem> getSaleLineItems() throws SQLException {
|
|
||||||
ObservableList<SaleLineItem> 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<SaleCartItem> 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<DailySalesData> getDailySalesRevenue() throws SQLException {
|
|
||||||
ObservableList<DailySalesData> 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<ProductSalesData> getTopProductsByRevenue(int limit) throws SQLException {
|
|
||||||
ObservableList<ProductSalesData> 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<ProductSalesData> getTopProductsByQuantity(int limit) throws SQLException {
|
|
||||||
ObservableList<ProductSalesData> 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<PaymentMethodData> getPaymentMethodDistribution() throws SQLException {
|
|
||||||
ObservableList<PaymentMethodData> 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<EmployeeSalesData> getEmployeeSalesPerformance() throws SQLException {
|
|
||||||
ObservableList<EmployeeSalesData> 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<SaleCartItem> 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<Service> getServices() throws SQLException {
|
|
||||||
|
|
||||||
ObservableList<Service> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<Supplier> getSuppliers() throws SQLException {
|
|
||||||
//Connect to the database
|
|
||||||
ObservableList<Supplier> 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<Supplier> getFilteredSuppliers(String filter) throws SQLException {
|
|
||||||
//Connect to the database
|
|
||||||
ObservableList<Supplier> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<StaffAccount> 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<StaffAccount> 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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,16 +8,17 @@ public class Adoption {
|
|||||||
private SimpleIntegerProperty adoptionId;
|
private SimpleIntegerProperty adoptionId;
|
||||||
private SimpleIntegerProperty petId;
|
private SimpleIntegerProperty petId;
|
||||||
private SimpleIntegerProperty customerId;
|
private SimpleIntegerProperty customerId;
|
||||||
|
private SimpleStringProperty petName;
|
||||||
private SimpleStringProperty customerName;
|
private SimpleStringProperty customerName;
|
||||||
private SimpleStringProperty adoptionDate;
|
private SimpleStringProperty adoptionDate;
|
||||||
private SimpleDoubleProperty adoptionFee;
|
private SimpleDoubleProperty adoptionFee;
|
||||||
private SimpleStringProperty adoptionStatus;
|
private SimpleStringProperty adoptionStatus;
|
||||||
|
|
||||||
//Constructor
|
public Adoption(int adoptionId, int petId, int customerId, String petName, String customerName, String adoptionDate, double adoptionFee, String adoptionStatus) {
|
||||||
public Adoption(int adoptionId, int petId, int customerId, String customerName, String adoptionDate, double adoptionFee, String adoptionStatus) {
|
|
||||||
this.adoptionId = new SimpleIntegerProperty(adoptionId);
|
this.adoptionId = new SimpleIntegerProperty(adoptionId);
|
||||||
this.petId = new SimpleIntegerProperty(petId);
|
this.petId = new SimpleIntegerProperty(petId);
|
||||||
this.customerId = new SimpleIntegerProperty(customerId);
|
this.customerId = new SimpleIntegerProperty(customerId);
|
||||||
|
this.petName = new SimpleStringProperty(petName);
|
||||||
this.customerName = new SimpleStringProperty(customerName);
|
this.customerName = new SimpleStringProperty(customerName);
|
||||||
this.adoptionDate = new SimpleStringProperty(adoptionDate);
|
this.adoptionDate = new SimpleStringProperty(adoptionDate);
|
||||||
this.adoptionFee = new SimpleDoubleProperty(adoptionFee);
|
this.adoptionFee = new SimpleDoubleProperty(adoptionFee);
|
||||||
@@ -42,6 +43,12 @@ public class Adoption {
|
|||||||
|
|
||||||
public SimpleIntegerProperty customerIdProperty() { return customerId; }
|
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 String getCustomerName() { return customerName.get(); }
|
||||||
|
|
||||||
public void setCustomerName(String customerName) { this.customerName.set(customerName); }
|
public void setCustomerName(String customerName) { this.customerName.set(customerName); }
|
||||||
|
|||||||
@@ -7,14 +7,21 @@ public class Inventory {
|
|||||||
private SimpleIntegerProperty inventoryId;
|
private SimpleIntegerProperty inventoryId;
|
||||||
private SimpleIntegerProperty prodId;
|
private SimpleIntegerProperty prodId;
|
||||||
private SimpleStringProperty prodName;
|
private SimpleStringProperty prodName;
|
||||||
|
private SimpleStringProperty categoryName;
|
||||||
|
private SimpleIntegerProperty storeId;
|
||||||
|
private SimpleStringProperty storeName;
|
||||||
private SimpleIntegerProperty quantity;
|
private SimpleIntegerProperty quantity;
|
||||||
|
private SimpleIntegerProperty reorderLevel;
|
||||||
|
|
||||||
//Constructor
|
public Inventory(int inventoryId, int prodId, String prodName, String categoryName, int storeId, String storeName, int quantity, int reorderLevel) {
|
||||||
public Inventory(int inventoryId, int prodId, String prodName, int quantity) {
|
|
||||||
this.inventoryId = new SimpleIntegerProperty(inventoryId);
|
this.inventoryId = new SimpleIntegerProperty(inventoryId);
|
||||||
this.prodId = new SimpleIntegerProperty(prodId);
|
this.prodId = new SimpleIntegerProperty(prodId);
|
||||||
this.prodName = new SimpleStringProperty(prodName);
|
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.quantity = new SimpleIntegerProperty(quantity);
|
||||||
|
this.reorderLevel = new SimpleIntegerProperty(reorderLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getInventoryId() { return inventoryId.get(); }
|
public int getInventoryId() { return inventoryId.get(); }
|
||||||
@@ -35,9 +42,33 @@ public class Inventory {
|
|||||||
|
|
||||||
public SimpleStringProperty prodNameProperty() { return prodName; }
|
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 int getQuantity() { return quantity.get(); }
|
||||||
|
|
||||||
public void setQuantity(int quantity) { this.quantity.set(quantity); }
|
public void setQuantity(int quantity) { this.quantity.set(quantity); }
|
||||||
|
|
||||||
public SimpleIntegerProperty quantityProperty() { return 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; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +1,52 @@
|
|||||||
package org.example.petshopdesktop.models;
|
package org.example.petshopdesktop.models;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
public class PurchaseOrder {
|
public class PurchaseOrder {
|
||||||
|
|
||||||
private int purchaseOrderId;
|
private long purchaseOrderId;
|
||||||
private int supId;
|
private String supplierName;
|
||||||
private String orderDate;
|
private LocalDate orderDate;
|
||||||
|
private LocalDate expectedDeliveryDate;
|
||||||
private String status;
|
private String status;
|
||||||
|
private BigDecimal totalAmount;
|
||||||
|
|
||||||
public PurchaseOrder(int purchaseOrderId,
|
public PurchaseOrder(long purchaseOrderId,
|
||||||
int supId,
|
String supplierName,
|
||||||
String orderDate,
|
LocalDate orderDate,
|
||||||
String status) {
|
LocalDate expectedDeliveryDate,
|
||||||
|
String status,
|
||||||
|
BigDecimal totalAmount) {
|
||||||
this.purchaseOrderId = purchaseOrderId;
|
this.purchaseOrderId = purchaseOrderId;
|
||||||
this.supId = supId;
|
this.supplierName = supplierName;
|
||||||
this.orderDate = orderDate;
|
this.orderDate = orderDate;
|
||||||
|
this.expectedDeliveryDate = expectedDeliveryDate;
|
||||||
this.status = status;
|
this.status = status;
|
||||||
|
this.totalAmount = totalAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPurchaseOrderId() {
|
public long getPurchaseOrderId() {
|
||||||
return purchaseOrderId;
|
return purchaseOrderId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSupId() {
|
public String getSupplierName() {
|
||||||
return supId;
|
return supplierName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getOrderDate() {
|
public LocalDate getOrderDate() {
|
||||||
return orderDate;
|
return orderDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LocalDate getExpectedDeliveryDate() {
|
||||||
|
return expectedDeliveryDate;
|
||||||
|
}
|
||||||
|
|
||||||
public String getStatus() {
|
public String getStatus() {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BigDecimal getTotalAmount() {
|
||||||
|
return totalAmount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -3,8 +3,8 @@ package org.example.petshopdesktop.models;
|
|||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
|
|
||||||
public class StaffAccount {
|
public class StaffAccount {
|
||||||
private final int userId;
|
private final long userId;
|
||||||
private final int employeeId;
|
private final long employeeId;
|
||||||
private final String username;
|
private final String username;
|
||||||
private final String firstName;
|
private final String firstName;
|
||||||
private final String lastName;
|
private final String lastName;
|
||||||
@@ -13,7 +13,7 @@ public class StaffAccount {
|
|||||||
private final boolean active;
|
private final boolean active;
|
||||||
private final Timestamp createdAt;
|
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.userId = userId;
|
||||||
this.employeeId = employeeId;
|
this.employeeId = employeeId;
|
||||||
this.username = username;
|
this.username = username;
|
||||||
@@ -25,11 +25,11 @@ public class StaffAccount {
|
|||||||
this.createdAt = createdAt;
|
this.createdAt = createdAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getUserId() {
|
public long getUserId() {
|
||||||
return userId;
|
return userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getEmployeeId() {
|
public long getEmployeeId() {
|
||||||
return employeeId;
|
return employeeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user