From d0ae7bc57c084f27c730dcb54750d32ffe166ad8 Mon Sep 17 00:00:00 2001 From: nilangadilhara Date: Tue, 4 Nov 2025 19:19:08 +0530 Subject: [PATCH 1/2] Add admin CRUD functionality with complete implementation - Added full CRUD operations for appointments, projects, tasks, and employees - Implemented AdminController with 28 REST endpoints - Created AdminService interface and implementation with business logic - Enhanced all entity models with relationships and fields - Added DTOs for data transfer (AppointmentDTO, ProjectDTO, TaskDTO, EmployeeDTO) - Defined status enums (AppointmentStatus, ProjectStatus, TaskStatus) - Updated repositories with custom query methods - Added comprehensive documentation files - Created test-data.sql for sample data --- ADMIN_CRUD_API_GUIDE.md | 464 ++++++++++++++++++ ADMIN_IMPLEMENTATION_GUIDE.md | 242 +++++++++ API_TEST_EXAMPLES.md | 292 +++++++++++ ARCHITECTURE.md | 396 +++++++++++++++ IMPLEMENTATION_SUMMARY.md | 179 +++++++ .../controller/AdminController.java | 392 ++++++++++++++- .../ead_backend/dto/AppointmentDTO.java | 21 +- .../example/ead_backend/dto/EmployeeDTO.java | 18 +- .../example/ead_backend/dto/ProjectDTO.java | 23 +- .../com/example/ead_backend/dto/TaskDTO.java | 21 +- .../ead_backend/model/entity/Appointment.java | 23 + .../ead_backend/model/entity/Employee.java | 22 + .../ead_backend/model/entity/Project.java | 27 + .../ead_backend/model/entity/Task.java | 23 + .../model/enums/AppointmentStatus.java | 13 +- .../model/enums/ProjectStatus.java | 11 +- .../ead_backend/model/enums/TaskStatus.java | 8 +- .../repository/AppointmentRepository.java | 13 + .../repository/EmployeeRepository.java | 14 +- .../repository/ProjectRepository.java | 13 + .../repository/TaskRepository.java | 10 + .../ead_backend/service/AdminService.java | 40 +- .../service/impl/AdminServiceImpl.java | 443 ++++++++++++++++- src/main/resources/application.properties | 4 +- test-data.sql | 174 +++++++ 25 files changed, 2861 insertions(+), 25 deletions(-) create mode 100644 ADMIN_CRUD_API_GUIDE.md create mode 100644 ADMIN_IMPLEMENTATION_GUIDE.md create mode 100644 API_TEST_EXAMPLES.md create mode 100644 ARCHITECTURE.md create mode 100644 IMPLEMENTATION_SUMMARY.md create mode 100644 test-data.sql diff --git a/ADMIN_CRUD_API_GUIDE.md b/ADMIN_CRUD_API_GUIDE.md new file mode 100644 index 0000000..20d4c26 --- /dev/null +++ b/ADMIN_CRUD_API_GUIDE.md @@ -0,0 +1,464 @@ +# Admin CRUD Operations - Complete API Guide + +## Overview +This document provides complete CRUD (Create, Read, Update, Delete) operations for the admin module. + +## Base URL +``` +http://localhost:8080/api/admin +``` + +--- + +## πŸ“‹ Appointment CRUD Operations + +### 1. Get All Pending Appointments +```http +GET /api/admin/appointments/pending +``` +**Response**: List of pending appointments (status = PENDING) + +### 2. Get All Appointments +```http +GET /api/admin/appointments +``` +**Response**: List of all appointments + +### 3. Get Appointment by ID +```http +GET /api/admin/appointments/{appointmentId} +``` +**Response**: Single appointment details + +### 4. Create Appointment +```http +POST /api/admin/appointments +Content-Type: application/json + +{ + "customerId": "CUST001", + "vehicleId": "VEH001", + "description": "Oil change and tire rotation", + "appointmentDateTime": "2025-11-15T10:00:00", + "status": "PENDING" +} +``` +**Response**: Created appointment with generated ID + +### 5. Update Appointment +```http +PUT /api/admin/appointments/{appointmentId} +Content-Type: application/json + +{ + "description": "Updated description", + "appointmentDateTime": "2025-11-16T10:00:00", + "status": "CONFIRMED" +} +``` +**Response**: Updated appointment details + +### 6. Delete Appointment +```http +DELETE /api/admin/appointments/{appointmentId} +``` +**Response**: 204 No Content + +### 7. Assign Appointment to Employee +```http +PUT /api/admin/appointments/{appointmentId}/assign/{employeeId} +``` +**Response**: Appointment with status changed to ASSIGNED + +--- + +## πŸš€ Project CRUD Operations + +### 1. Get All Pending Projects +```http +GET /api/admin/projects/pending +``` +**Response**: List of pending projects (status = PENDING) + +### 2. Get All Projects +```http +GET /api/admin/projects +``` +**Response**: List of all projects + +### 3. Get Project by ID +```http +GET /api/admin/projects/{projectId} +``` +**Response**: Single project details + +### 4. Create Project +```http +POST /api/admin/projects +Content-Type: application/json + +{ + "customerId": "CUST001", + "vehicleId": "VEH001", + "projectName": "Engine Overhaul", + "description": "Complete engine rebuild", + "startDate": "2025-11-20T08:00:00", + "expectedEndDate": "2025-11-27T17:00:00", + "status": "PENDING" +} +``` +**Response**: Created project with generated ID + +### 5. Update Project +```http +PUT /api/admin/projects/{projectId} +Content-Type: application/json + +{ + "projectName": "Updated Engine Overhaul", + "description": "Updated description", + "expectedEndDate": "2025-11-28T17:00:00", + "status": "IN_PROGRESS" +} +``` +**Response**: Updated project details + +### 6. Delete Project +```http +DELETE /api/admin/projects/{projectId} +``` +**Response**: 204 No Content + +### 7. Assign Project to Employee +```http +PUT /api/admin/projects/{projectId}/assign/{employeeId} +``` +**Response**: Project with status changed to ASSIGNED + +--- + +## βœ… Task CRUD Operations + +### 1. Get All Tasks for Appointment +```http +GET /api/admin/appointments/{appointmentId}/tasks +``` +**Response**: List of all tasks under the appointment + +### 2. Get Task by ID +```http +GET /api/admin/tasks/{taskId} +``` +**Response**: Single task details + +### 3. Create Task +```http +POST /api/admin/tasks +Content-Type: application/json + +{ + "appointmentId": "APT001", + "taskName": "Replace oil filter", + "description": "Remove old filter and install new one", + "assignedEmployeeId": "EMP001", + "status": "TODO", + "dueDate": "2025-11-15T12:00:00" +} +``` +**Response**: Created task with generated ID + +### 4. Update Task +```http +PUT /api/admin/tasks/{taskId} +Content-Type: application/json + +{ + "taskName": "Updated task name", + "description": "Updated description", + "status": "IN_PROGRESS", + "dueDate": "2025-11-16T12:00:00" +} +``` +**Response**: Updated task details + +### 5. Delete Task +```http +DELETE /api/admin/tasks/{taskId} +``` +**Response**: 204 No Content + +--- + +## πŸ‘₯ Employee CRUD Operations + +### 1. Get All Available Employees +```http +GET /api/admin/employees/available +``` +**Response**: List of employees where isAvailable = true + +### 2. Get All Employees +```http +GET /api/admin/employees +``` +**Response**: List of all employees + +### 3. Get Employee by ID +```http +GET /api/admin/employees/{employeeId} +``` +**Response**: Single employee details + +### 4. Create Employee +```http +POST /api/admin/employees +Content-Type: application/json + +{ + "name": "John Doe", + "email": "john.doe@example.com", + "phone": "+1234567890", + "specialization": "Engine Specialist", + "isAvailable": true +} +``` +**Response**: Created employee with generated ID + +### 5. Update Employee +```http +PUT /api/admin/employees/{employeeId} +Content-Type: application/json + +{ + "name": "John Doe Updated", + "email": "john.updated@example.com", + "phone": "+1234567899", + "specialization": "Senior Engine Specialist", + "isAvailable": false +} +``` +**Response**: Updated employee details + +### 6. Delete Employee +```http +DELETE /api/admin/employees/{employeeId} +``` +**Response**: 204 No Content + +--- + +## PowerShell Testing Examples + +### Appointment Operations +```powershell +# Create Appointment +$appointmentBody = @{ + customerId = "CUST001" + vehicleId = "VEH001" + description = "Oil change" + appointmentDateTime = "2025-11-15T10:00:00" + status = "PENDING" +} | ConvertTo-Json + +Invoke-RestMethod -Uri "http://localhost:8080/api/admin/appointments" ` + -Method Post ` + -Body $appointmentBody ` + -ContentType "application/json" + +# Update Appointment +$updateBody = @{ + description = "Oil change and tire rotation" + status = "CONFIRMED" +} | ConvertTo-Json + +Invoke-RestMethod -Uri "http://localhost:8080/api/admin/appointments/APT001" ` + -Method Put ` + -Body $updateBody ` + -ContentType "application/json" + +# Delete Appointment +Invoke-RestMethod -Uri "http://localhost:8080/api/admin/appointments/APT001" ` + -Method Delete +``` + +### Project Operations +```powershell +# Create Project +$projectBody = @{ + customerId = "CUST001" + vehicleId = "VEH001" + projectName = "Engine Overhaul" + description = "Complete engine rebuild" + startDate = "2025-11-20T08:00:00" + expectedEndDate = "2025-11-27T17:00:00" + status = "PENDING" +} | ConvertTo-Json + +Invoke-RestMethod -Uri "http://localhost:8080/api/admin/projects" ` + -Method Post ` + -Body $projectBody ` + -ContentType "application/json" + +# Update Project +$updateProjectBody = @{ + projectName = "Updated Engine Overhaul" + status = "IN_PROGRESS" +} | ConvertTo-Json + +Invoke-RestMethod -Uri "http://localhost:8080/api/admin/projects/PRJ001" ` + -Method Put ` + -Body $updateProjectBody ` + -ContentType "application/json" + +# Delete Project +Invoke-RestMethod -Uri "http://localhost:8080/api/admin/projects/PRJ001" ` + -Method Delete +``` + +### Task Operations +```powershell +# Create Task +$taskBody = @{ + appointmentId = "APT001" + taskName = "Replace oil filter" + description = "Remove old and install new" + assignedEmployeeId = "EMP001" + status = "TODO" + dueDate = "2025-11-15T12:00:00" +} | ConvertTo-Json + +Invoke-RestMethod -Uri "http://localhost:8080/api/admin/tasks" ` + -Method Post ` + -Body $taskBody ` + -ContentType "application/json" + +# Get Tasks for Appointment +Invoke-RestMethod -Uri "http://localhost:8080/api/admin/appointments/APT001/tasks" ` + -Method Get + +# Update Task +$updateTaskBody = @{ + status = "IN_PROGRESS" +} | ConvertTo-Json + +Invoke-RestMethod -Uri "http://localhost:8080/api/admin/tasks/TASK001" ` + -Method Put ` + -Body $updateTaskBody ` + -ContentType "application/json" + +# Delete Task +Invoke-RestMethod -Uri "http://localhost:8080/api/admin/tasks/TASK001" ` + -Method Delete +``` + +### Employee Operations +```powershell +# Create Employee +$employeeBody = @{ + name = "John Doe" + email = "john.doe@example.com" + phone = "+1234567890" + specialization = "Engine Specialist" + isAvailable = $true +} | ConvertTo-Json + +Invoke-RestMethod -Uri "http://localhost:8080/api/admin/employees" ` + -Method Post ` + -Body $employeeBody ` + -ContentType "application/json" + +# Update Employee +$updateEmployeeBody = @{ + name = "John Doe Updated" + isAvailable = $false +} | ConvertTo-Json + +Invoke-RestMethod -Uri "http://localhost:8080/api/admin/employees/EMP001" ` + -Method Put ` + -Body $updateEmployeeBody ` + -ContentType "application/json" + +# Delete Employee +Invoke-RestMethod -Uri "http://localhost:8080/api/admin/employees/EMP001" ` + -Method Delete +``` + +--- + +## HTTP Status Codes + +| Code | Meaning | +|------|---------| +| 200 OK | Request successful | +| 201 Created | Resource created successfully | +| 204 No Content | Delete successful (no response body) | +| 400 Bad Request | Invalid data or business rule violation | +| 404 Not Found | Resource not found | +| 500 Internal Server Error | Server error | + +--- + +## Complete Endpoint Summary + +| Method | Endpoint | Description | +|--------|----------|-------------| +| **Appointments** | | | +| GET | `/api/admin/appointments/pending` | Get pending appointments | +| GET | `/api/admin/appointments` | Get all appointments | +| GET | `/api/admin/appointments/{id}` | Get appointment by ID | +| POST | `/api/admin/appointments` | Create appointment | +| PUT | `/api/admin/appointments/{id}` | Update appointment | +| DELETE | `/api/admin/appointments/{id}` | Delete appointment | +| PUT | `/api/admin/appointments/{id}/assign/{empId}` | Assign to employee | +| **Projects** | | | +| GET | `/api/admin/projects/pending` | Get pending projects | +| GET | `/api/admin/projects` | Get all projects | +| GET | `/api/admin/projects/{id}` | Get project by ID | +| POST | `/api/admin/projects` | Create project | +| PUT | `/api/admin/projects/{id}` | Update project | +| DELETE | `/api/admin/projects/{id}` | Delete project | +| PUT | `/api/admin/projects/{id}/assign/{empId}` | Assign to employee | +| **Tasks** | | | +| GET | `/api/admin/appointments/{id}/tasks` | Get tasks for appointment | +| GET | `/api/admin/tasks/{id}` | Get task by ID | +| POST | `/api/admin/tasks` | Create task | +| PUT | `/api/admin/tasks/{id}` | Update task | +| DELETE | `/api/admin/tasks/{id}` | Delete task | +| **Employees** | | | +| GET | `/api/admin/employees/available` | Get available employees | +| GET | `/api/admin/employees` | Get all employees | +| GET | `/api/admin/employees/{id}` | Get employee by ID | +| POST | `/api/admin/employees` | Create employee | +| PUT | `/api/admin/employees/{id}` | Update employee | +| DELETE | `/api/admin/employees/{id}` | Delete employee | + +--- + +## Status Values Reference + +### Appointment Status +- `PENDING` - Created, waiting for assignment +- `ASSIGNED` - Assigned to employee +- `CONFIRMED` - Employee confirmed +- `IN_PROGRESS` - Work in progress +- `COMPLETED` - Work completed +- `CANCELLED` - Cancelled +- `NO_SHOW` - Customer didn't show + +### Project Status +- `PENDING` - Created, waiting for assignment +- `ASSIGNED` - Assigned to employee +- `IN_PROGRESS` - Work in progress +- `COMPLETED` - Work completed +- `CANCELLED` - Cancelled +- `ON_HOLD` - Temporarily paused + +### Task Status +- `TODO` - Not started +- `IN_PROGRESS` - Being worked on +- `COMPLETED` - Finished +- `CANCELLED` - Cancelled + +--- + +**Total Endpoints**: 28 REST API endpoints for complete admin CRUD operations! diff --git a/ADMIN_IMPLEMENTATION_GUIDE.md b/ADMIN_IMPLEMENTATION_GUIDE.md new file mode 100644 index 0000000..df27c96 --- /dev/null +++ b/ADMIN_IMPLEMENTATION_GUIDE.md @@ -0,0 +1,242 @@ +# Admin Module Implementation Guide + +## Overview +This document describes the admin functionality implementation for the EAD Automobile System. The admin module allows administrators to view appointments and projects created by customers and assign them to available employees. + +## Implementation Summary + +### 1. Entity Models Updated + +#### Appointment Entity +- **Location**: `src/main/java/com/example/ead_backend/model/entity/Appointment.java` +- **Fields Added**: + - `customerId`: Reference to the customer who created the appointment + - `vehicleId`: Vehicle for which appointment is created + - `description`: Appointment details + - `appointmentDateTime`: Scheduled date and time + - `status`: Current status (PENDING, ASSIGNED, CONFIRMED, etc.) + - `assignedEmployeeId`: Employee assigned to handle the appointment + - `createdAt`, `updatedAt`: Timestamps + - `assignedEmployee`: ManyToOne relationship with Employee + +#### Project Entity +- **Location**: `src/main/java/com/example/ead_backend/model/entity/Project.java` +- **Fields Added**: + - `customerId`: Reference to the customer who created the project + - `vehicleId`: Vehicle for the project + - `projectName`: Name of the project + - `description`: Project details + - `startDate`, `expectedEndDate`: Project timeline + - `status`: Current status (PENDING, ASSIGNED, IN_PROGRESS, etc.) + - `assignedEmployeeId`: Employee assigned to handle the project + - `createdAt`, `updatedAt`: Timestamps + - `assignedEmployee`: ManyToOne relationship with Employee + +#### Employee Entity +- **Location**: `src/main/java/com/example/ead_backend/model/entity/Employee.java` +- **Fields Added**: + - `name`, `email`, `phone`: Employee contact information + - `specialization`: Employee's area of expertise + - `isAvailable`: Availability status for new assignments + - `createdAt`, `updatedAt`: Timestamps + - `appointments`, `projects`: OneToMany relationships + +### 2. Enums + +#### AppointmentStatus +- **Location**: `src/main/java/com/example/ead_backend/model/enums/AppointmentStatus.java` +- **Values**: + - `PENDING`: Created by customer, waiting for admin assignment + - `ASSIGNED`: Assigned to an employee by admin + - `CONFIRMED`: Employee confirmed the appointment + - `IN_PROGRESS`: Appointment in progress + - `COMPLETED`: Appointment completed + - `CANCELLED`: Appointment cancelled + - `NO_SHOW`: Customer didn't show up + +#### ProjectStatus +- **Location**: `src/main/java/com/example/ead_backend/model/enums/ProjectStatus.java` +- **Values**: + - `PENDING`: Created by customer, waiting for admin assignment + - `ASSIGNED`: Assigned to an employee by admin + - `IN_PROGRESS`: Project work in progress + - `COMPLETED`: Project completed + - `CANCELLED`: Project cancelled + - `ON_HOLD`: Project temporarily on hold + +### 3. DTOs (Data Transfer Objects) + +#### AppointmentDTO +- **Location**: `src/main/java/com/example/ead_backend/dto/AppointmentDTO.java` +- Used for transferring appointment data between layers + +#### ProjectDTO +- **Location**: `src/main/java/com/example/ead_backend/dto/ProjectDTO.java` +- Used for transferring project data between layers + +#### EmployeeDTO +- **Location**: `src/main/java/com/example/ead_backend/dto/EmployeeDTO.java` +- Used for transferring employee data between layers + +### 4. Repositories + +#### AppointmentRepository +- **Location**: `src/main/java/com/example/ead_backend/repository/AppointmentRepository.java` +- **Custom Methods**: + - `findByStatus(AppointmentStatus status)`: Find appointments by status + - `findByAssignedEmployeeId(String employeeId)`: Find appointments assigned to an employee + - `findAllPendingAppointments()`: Find all pending appointments + +#### ProjectRepository +- **Location**: `src/main/java/com/example/ead_backend/repository/ProjectRepository.java` +- **Custom Methods**: + - `findByStatus(ProjectStatus status)`: Find projects by status + - `findByAssignedEmployeeId(String employeeId)`: Find projects assigned to an employee + - `findAllPendingProjects()`: Find all pending projects + +#### EmployeeRepository +- **Location**: `src/main/java/com/example/ead_backend/repository/EmployeeRepository.java` +- **Custom Methods**: + - `findByIsAvailable(boolean isAvailable)`: Find available/unavailable employees + - `findBySpecializationAndIsAvailable(String specialization, boolean isAvailable)`: Find available employees by specialization + - `findAllAvailableEmployees()`: Find all available employees + +### 5. Service Layer + +#### AdminService Interface +- **Location**: `src/main/java/com/example/ead_backend/service/AdminService.java` +- **Methods**: + - Appointment Management: + - `getAllPendingAppointments()`: Get all unassigned appointments + - `getAllAppointments()`: Get all appointments + - `getAppointmentById(String appointmentId)`: Get specific appointment + - `assignAppointmentToEmployee(String appointmentId, String employeeId)`: Assign appointment + - Project Management: + - `getAllPendingProjects()`: Get all unassigned projects + - `getAllProjects()`: Get all projects + - `getProjectById(String projectId)`: Get specific project + - `assignProjectToEmployee(String projectId, String employeeId)`: Assign project + - Employee Management: + - `getAllAvailableEmployees()`: Get all available employees + - `getAllEmployees()`: Get all employees + - `getEmployeeById(String employeeId)`: Get specific employee + +#### AdminServiceImpl +- **Location**: `src/main/java/com/example/ead_backend/service/impl/AdminServiceImpl.java` +- Implements all AdminService interface methods +- Includes validation logic (e.g., checking employee availability) +- Includes DTO conversion methods +- Updates status when assigning appointments/projects + +### 6. Controller Layer + +#### AdminController +- **Location**: `src/main/java/com/example/ead_backend/controller/AdminController.java` +- **Base URL**: `/api/admin` +- **Endpoints**: + +##### Appointment Endpoints +- `GET /api/admin/appointments/pending`: Get all pending appointments +- `GET /api/admin/appointments`: Get all appointments +- `GET /api/admin/appointments/{appointmentId}`: Get appointment by ID +- `PUT /api/admin/appointments/{appointmentId}/assign/{employeeId}`: Assign appointment to employee + +##### Project Endpoints +- `GET /api/admin/projects/pending`: Get all pending projects +- `GET /api/admin/projects`: Get all projects +- `GET /api/admin/projects/{projectId}`: Get project by ID +- `PUT /api/admin/projects/{projectId}/assign/{employeeId}`: Assign project to employee + +##### Employee Endpoints +- `GET /api/admin/employees/available`: Get all available employees +- `GET /api/admin/employees`: Get all employees +- `GET /api/admin/employees/{employeeId}`: Get employee by ID + +## API Usage Examples + +### 1. Get All Pending Appointments +```http +GET http://localhost:8080/api/admin/appointments/pending +``` + +### 2. Get All Available Employees +```http +GET http://localhost:8080/api/admin/employees/available +``` + +### 3. Assign Appointment to Employee +```http +PUT http://localhost:8080/api/admin/appointments/APT001/assign/EMP001 +``` + +### 4. Get All Pending Projects +```http +GET http://localhost:8080/api/admin/projects/pending +``` + +### 5. Assign Project to Employee +```http +PUT http://localhost:8080/api/admin/projects/PRJ001/assign/EMP001 +``` + +## Workflow + +1. **Customer Creates Appointment/Project**: + - Customer creates an appointment or project through their interface (implemented by your team member) + - Status is set to `PENDING` + - `assignedEmployeeId` is `null` + +2. **Admin Views Pending Items**: + - Admin accesses `/api/admin/appointments/pending` or `/api/admin/projects/pending` + - System returns all appointments/projects with `PENDING` status + +3. **Admin Checks Available Employees**: + - Admin accesses `/api/admin/employees/available` + - System returns employees where `isAvailable = true` + +4. **Admin Assigns to Employee**: + - Admin calls assignment endpoint with appointmentId/projectId and employeeId + - System validates: + - Appointment/Project exists + - Employee exists + - Employee is available + - Updates status to `ASSIGNED` + - Sets `assignedEmployeeId` + - Updates `updatedAt` timestamp + +5. **Employee Handles Assignment**: + - Employee can view their assigned appointments/projects + - Employee updates status as work progresses + +## Error Handling + +The implementation includes proper error handling: +- `404 NOT_FOUND`: When appointment/project/employee doesn't exist +- `400 BAD_REQUEST`: When trying to assign to unavailable employee or invalid data +- `500 INTERNAL_SERVER_ERROR`: For unexpected errors + +## Notes for Integration + +1. **Your team member's part** (Customer creating appointments/projects) should: + - Set `status = AppointmentStatus.PENDING` or `ProjectStatus.PENDING` + - Leave `assignedEmployeeId` as `null` + - Set `createdAt` to current timestamp + +2. **Database Configuration**: + - Ensure your `application.properties` has correct database settings + - Run the application to auto-create tables (if using `spring.jpa.hibernate.ddl-auto=update`) + +3. **Testing**: + - Test with sample data + - Ensure appointments/projects are created with PENDING status + - Verify admin can fetch and assign them + +## Future Enhancements + +Consider implementing: +1. Email notifications to employees when assigned +2. Workload calculation for employees +3. Auto-assignment based on availability and specialization +4. Dashboard with statistics +5. Reassignment functionality +6. Appointment/Project history tracking diff --git a/API_TEST_EXAMPLES.md b/API_TEST_EXAMPLES.md new file mode 100644 index 0000000..b616e33 --- /dev/null +++ b/API_TEST_EXAMPLES.md @@ -0,0 +1,292 @@ +# API Testing Examples for Admin Module + +This file contains example requests for testing the Admin Module APIs using tools like Postman, cURL, or REST Client. + +## Prerequisites +- Application should be running on `http://localhost:8080` +- Database should have some test data + +## 1. Appointment Management APIs + +### 1.1 Get All Pending Appointments +**Request:** +```http +GET http://localhost:8080/api/admin/appointments/pending +Accept: application/json +``` + +**Expected Response (200 OK):** +```json +[ + { + "appointmentId": "APT001", + "customerId": "CUST001", + "vehicleId": "VEH001", + "description": "Regular service check", + "appointmentDateTime": "2025-11-10T10:00:00", + "status": "PENDING", + "assignedEmployeeId": null, + "assignedEmployeeName": null, + "createdAt": "2025-11-04T09:00:00", + "updatedAt": "2025-11-04T09:00:00" + } +] +``` + +### 1.2 Get All Appointments +**Request:** +```http +GET http://localhost:8080/api/admin/appointments +Accept: application/json +``` + +### 1.3 Get Appointment by ID +**Request:** +```http +GET http://localhost:8080/api/admin/appointments/APT001 +Accept: application/json +``` + +### 1.4 Assign Appointment to Employee +**Request:** +```http +PUT http://localhost:8080/api/admin/appointments/APT001/assign/EMP001 +Accept: application/json +``` + +**Expected Response (200 OK):** +```json +{ + "appointmentId": "APT001", + "customerId": "CUST001", + "vehicleId": "VEH001", + "description": "Regular service check", + "appointmentDateTime": "2025-11-10T10:00:00", + "status": "ASSIGNED", + "assignedEmployeeId": "EMP001", + "assignedEmployeeName": "John Doe", + "createdAt": "2025-11-04T09:00:00", + "updatedAt": "2025-11-04T14:30:00" +} +``` + +**Error Response (400 BAD REQUEST):** +```json +{ + "message": "Employee is not available for assignment" +} +``` + +## 2. Project Management APIs + +### 2.1 Get All Pending Projects +**Request:** +```http +GET http://localhost:8080/api/admin/projects/pending +Accept: application/json +``` + +**Expected Response (200 OK):** +```json +[ + { + "projectId": "PRJ001", + "customerId": "CUST001", + "vehicleId": "VEH001", + "projectName": "Engine Overhaul", + "description": "Complete engine overhaul and maintenance", + "startDate": "2025-11-15T08:00:00", + "expectedEndDate": "2025-11-20T17:00:00", + "status": "PENDING", + "assignedEmployeeId": null, + "assignedEmployeeName": null, + "createdAt": "2025-11-04T10:00:00", + "updatedAt": "2025-11-04T10:00:00" + } +] +``` + +### 2.2 Get All Projects +**Request:** +```http +GET http://localhost:8080/api/admin/projects +Accept: application/json +``` + +### 2.3 Get Project by ID +**Request:** +```http +GET http://localhost:8080/api/admin/projects/PRJ001 +Accept: application/json +``` + +### 2.4 Assign Project to Employee +**Request:** +```http +PUT http://localhost:8080/api/admin/projects/PRJ001/assign/EMP002 +Accept: application/json +``` + +**Expected Response (200 OK):** +```json +{ + "projectId": "PRJ001", + "customerId": "CUST001", + "vehicleId": "VEH001", + "projectName": "Engine Overhaul", + "description": "Complete engine overhaul and maintenance", + "startDate": "2025-11-15T08:00:00", + "expectedEndDate": "2025-11-20T17:00:00", + "status": "ASSIGNED", + "assignedEmployeeId": "EMP002", + "assignedEmployeeName": "Jane Smith", + "createdAt": "2025-11-04T10:00:00", + "updatedAt": "2025-11-04T14:45:00" +} +``` + +## 3. Employee Management APIs + +### 3.1 Get All Available Employees +**Request:** +```http +GET http://localhost:8080/api/admin/employees/available +Accept: application/json +``` + +**Expected Response (200 OK):** +```json +[ + { + "employeeId": "EMP001", + "name": "John Doe", + "email": "john.doe@example.com", + "phone": "+1234567890", + "specialization": "Engine Specialist", + "available": true, + "createdAt": "2025-11-01T08:00:00", + "updatedAt": "2025-11-01T08:00:00" + }, + { + "employeeId": "EMP002", + "name": "Jane Smith", + "email": "jane.smith@example.com", + "phone": "+1234567891", + "specialization": "Electrical Systems", + "available": true, + "createdAt": "2025-11-01T08:00:00", + "updatedAt": "2025-11-01T08:00:00" + } +] +``` + +### 3.2 Get All Employees +**Request:** +```http +GET http://localhost:8080/api/admin/employees +Accept: application/json +``` + +### 3.3 Get Employee by ID +**Request:** +```http +GET http://localhost:8080/api/admin/employees/EMP001 +Accept: application/json +``` + +**Expected Response (200 OK):** +```json +{ + "employeeId": "EMP001", + "name": "John Doe", + "email": "john.doe@example.com", + "phone": "+1234567890", + "specialization": "Engine Specialist", + "available": true, + "createdAt": "2025-11-01T08:00:00", + "updatedAt": "2025-11-01T08:00:00" +} +``` + +**Error Response (404 NOT FOUND):** +```json +{ + "message": "Employee not found with id: EMP999" +} +``` + +## cURL Commands + +### Get Pending Appointments +```bash +curl -X GET http://localhost:8080/api/admin/appointments/pending -H "Accept: application/json" +``` + +### Get Available Employees +```bash +curl -X GET http://localhost:8080/api/admin/employees/available -H "Accept: application/json" +``` + +### Assign Appointment to Employee +```bash +curl -X PUT http://localhost:8080/api/admin/appointments/APT001/assign/EMP001 -H "Accept: application/json" +``` + +### Get Pending Projects +```bash +curl -X GET http://localhost:8080/api/admin/projects/pending -H "Accept: application/json" +``` + +### Assign Project to Employee +```bash +curl -X PUT http://localhost:8080/api/admin/projects/PRJ001/assign/EMP002 -H "Accept: application/json" +``` + +## PowerShell Commands + +### Get Pending Appointments +```powershell +Invoke-RestMethod -Uri "http://localhost:8080/api/admin/appointments/pending" -Method Get -Headers @{"Accept"="application/json"} +``` + +### Get Available Employees +```powershell +Invoke-RestMethod -Uri "http://localhost:8080/api/admin/employees/available" -Method Get -Headers @{"Accept"="application/json"} +``` + +### Assign Appointment to Employee +```powershell +Invoke-RestMethod -Uri "http://localhost:8080/api/admin/appointments/APT001/assign/EMP001" -Method Put -Headers @{"Accept"="application/json"} +``` + +## Testing Workflow + +1. **Setup Test Data**: Insert test data for customers, vehicles, employees, appointments, and projects +2. **Test Employee Listing**: Verify you can retrieve available employees +3. **Test Pending Items**: Verify you can retrieve pending appointments and projects +4. **Test Assignment**: Try assigning an appointment/project to an employee +5. **Test Validation**: Try assigning to non-existent or unavailable employee (should fail) +6. **Test Status Change**: Verify status changes from PENDING to ASSIGNED after assignment + +## Sample Test Data SQL + +```sql +-- Insert test employees +INSERT INTO Employees (employeeId, name, email, phone, specialization, isAvailable, createdAt, updatedAt) +VALUES +('EMP001', 'John Doe', 'john.doe@example.com', '+1234567890', 'Engine Specialist', true, NOW(), NOW()), +('EMP002', 'Jane Smith', 'jane.smith@example.com', '+1234567891', 'Electrical Systems', true, NOW(), NOW()), +('EMP003', 'Bob Wilson', 'bob.wilson@example.com', '+1234567892', 'Body Work', false, NOW(), NOW()); + +-- Insert test appointments +INSERT INTO Appointments (appointmentId, customerId, vehicleId, description, appointmentDateTime, status, createdAt, updatedAt) +VALUES +('APT001', 'CUST001', 'VEH001', 'Regular service check', '2025-11-10 10:00:00', 'PENDING', NOW(), NOW()), +('APT002', 'CUST002', 'VEH002', 'Oil change', '2025-11-11 14:00:00', 'PENDING', NOW(), NOW()); + +-- Insert test projects +INSERT INTO Projects (projectId, customerId, vehicleId, projectName, description, startDate, expectedEndDate, status, createdAt, updatedAt) +VALUES +('PRJ001', 'CUST001', 'VEH001', 'Engine Overhaul', 'Complete engine overhaul and maintenance', '2025-11-15 08:00:00', '2025-11-20 17:00:00', 'PENDING', NOW(), NOW()), +('PRJ002', 'CUST003', 'VEH003', 'Paint Job', 'Full body paint and detailing', '2025-11-12 09:00:00', '2025-11-14 16:00:00', 'PENDING', NOW(), NOW()); +``` diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..8f84c20 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,396 @@ +# System Architecture - Admin Module + +## Overview Diagram + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ FRONTEND (Your UI) β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ View β”‚ β”‚ View β”‚ β”‚ Assign β”‚ β”‚ +β”‚ β”‚ Pending β”‚ β”‚ Available β”‚ β”‚ To Employee β”‚ β”‚ +β”‚ β”‚ Appointments β”‚ β”‚ Employees β”‚ β”‚ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”‚ HTTP REST API + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ CONTROLLER LAYER β”‚ +β”‚ (AdminController.java) β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ REST Endpoints: β”‚ β”‚ +β”‚ β”‚ β€’ GET /api/admin/appointments/pending β”‚ β”‚ +β”‚ β”‚ β€’ GET /api/admin/projects/pending β”‚ β”‚ +β”‚ β”‚ β€’ GET /api/admin/employees/available β”‚ β”‚ +β”‚ β”‚ β€’ PUT /api/admin/appointments/{id}/assign/{empId} β”‚ β”‚ +β”‚ β”‚ β€’ PUT /api/admin/projects/{id}/assign/{empId} β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”‚ Calls Service Methods + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ SERVICE LAYER β”‚ +β”‚ (AdminService + AdminServiceImpl) β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ Business Logic: β”‚ β”‚ +β”‚ β”‚ β€’ Fetch pending appointments/projects β”‚ β”‚ +β”‚ β”‚ β€’ Validate employee availability β”‚ β”‚ +β”‚ β”‚ β€’ Assign appointments/projects β”‚ β”‚ +β”‚ β”‚ β€’ Update status (PENDING β†’ ASSIGNED) β”‚ β”‚ +β”‚ β”‚ β€’ Convert Entity ↔ DTO β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”‚ Uses Repositories + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ REPOSITORY LAYER β”‚ +β”‚ (AppointmentRepo, ProjectRepo, EmployeeRepo) β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ Appointment β”‚ β”‚ Project β”‚ β”‚ Employee β”‚ β”‚ +β”‚ β”‚ Repository β”‚ β”‚ Repository β”‚ β”‚ Repository β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ β€’ findPending β”‚ β”‚ β€’ findPending β”‚ β”‚ β€’ findAvail β”‚ β”‚ +β”‚ β”‚ β€’ findByStatus β”‚ β”‚ β€’ findByStatus β”‚ β”‚ β€’ findBySpec β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”‚ JPA/Hibernate + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ DATABASE LAYER β”‚ +β”‚ (PostgreSQL Database) β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ Appointments β”‚ β”‚ Projects β”‚ β”‚ Employees β”‚ β”‚ +β”‚ β”‚ Table β”‚ β”‚ Table β”‚ β”‚ Table β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ β€’ appointmentId β”‚ β”‚ β€’ projectId β”‚ β”‚ β€’ employeeId β”‚ β”‚ +β”‚ β”‚ β€’ customerId β”‚ β”‚ β€’ customerId β”‚ β”‚ β€’ name β”‚ β”‚ +β”‚ β”‚ β€’ status β”‚ β”‚ β€’ status β”‚ β”‚ β€’ isAvailable β”‚ β”‚ +β”‚ β”‚ β€’ assignedEmpId β”‚ β”‚ β€’ assignedEmpId β”‚ β”‚ β€’ special... β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +## Data Flow Diagrams + +### 1. View Pending Appointments Flow + +``` +Admin UI + β”‚ + β”‚ GET /api/admin/appointments/pending + β”‚ + β–Ό +AdminController + β”‚ + β”‚ getAllPendingAppointments() + β”‚ + β–Ό +AdminService + β”‚ + β”‚ findAllPendingAppointments() + β”‚ + β–Ό +AppointmentRepository + β”‚ + β”‚ Query: WHERE status = 'PENDING' + β”‚ + β–Ό +Database + β”‚ + β”‚ Returns List + β”‚ + β–Ό +AdminService + β”‚ + β”‚ Convert to List + β”‚ + β–Ό +AdminController + β”‚ + β”‚ Return JSON Response + β”‚ + β–Ό +Admin UI (Displays pending appointments) +``` + +### 2. Assign Appointment Flow + +``` +Admin UI + β”‚ + β”‚ PUT /api/admin/appointments/APT001/assign/EMP001 + β”‚ + β–Ό +AdminController + β”‚ + β”‚ assignAppointmentToEmployee(APT001, EMP001) + β”‚ + β–Ό +AdminService + β”‚ + β”œβ”€β–Ί appointmentRepository.findById(APT001) + β”‚ └─► Appointment found + β”‚ + β”œβ”€β–Ί employeeRepository.findById(EMP001) + β”‚ └─► Employee found + β”‚ + β”œβ”€β–Ί Validate: employee.isAvailable? + β”‚ └─► Yes, proceed + β”‚ + β”œβ”€β–Ί appointment.setAssignedEmployeeId(EMP001) + β”œβ”€β–Ί appointment.setStatus(ASSIGNED) + β”œβ”€β–Ί appointment.setUpdatedAt(now) + β”‚ + β”œβ”€β–Ί appointmentRepository.save(appointment) + β”‚ └─► Saved to Database + β”‚ + └─► Convert to AppointmentDTO + β”‚ + β–Ό +AdminController + β”‚ + β”‚ Return JSON Response (Status: ASSIGNED) + β”‚ + β–Ό +Admin UI (Shows assignment success) +``` + +### 3. Integration Flow (Full System) + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ CUSTOMER MODULE β”‚ +β”‚ (Your Team Member's Part) β”‚ +β”‚ β”‚ +β”‚ Customer creates Appointment/Project β”‚ +β”‚ β”œβ”€β–Ί status = PENDING β”‚ +β”‚ β”œβ”€β–Ί assignedEmployeeId = NULL β”‚ +β”‚ └─► Saved to Database β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”‚ Data exists in DB + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ ADMIN MODULE β”‚ +β”‚ (Your Part - Now) β”‚ +β”‚ β”‚ +β”‚ Admin Views Pending Items β”‚ +β”‚ β”œβ”€β–Ί Fetches from Database β”‚ +β”‚ └─► Displays in UI β”‚ +β”‚ β”‚ +β”‚ Admin Views Available Employees β”‚ +β”‚ β”œβ”€β–Ί Fetches employees where isAvailable = true β”‚ +β”‚ └─► Displays in UI β”‚ +β”‚ β”‚ +β”‚ Admin Assigns to Employee β”‚ +β”‚ β”œβ”€β–Ί Validates employee availability β”‚ +β”‚ β”œβ”€β–Ί Updates assignedEmployeeId β”‚ +β”‚ β”œβ”€β–Ί Changes status: PENDING β†’ ASSIGNED β”‚ +β”‚ └─► Saves to Database β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”‚ Assignment complete + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ EMPLOYEE MODULE β”‚ +β”‚ (Future/Other Team Member) β”‚ +β”‚ β”‚ +β”‚ Employee Views Assigned Items β”‚ +β”‚ β”œβ”€β–Ί Query: WHERE assignedEmployeeId = {employeeId} β”‚ +β”‚ └─► Displays in UI β”‚ +β”‚ β”‚ +β”‚ Employee Updates Status β”‚ +β”‚ β”œβ”€β–Ί ASSIGNED β†’ CONFIRMED β”‚ +β”‚ β”œβ”€β–Ί CONFIRMED β†’ IN_PROGRESS β”‚ +β”‚ └─► IN_PROGRESS β†’ COMPLETED β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +## Entity Relationships + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Customer β”‚ +│─────────────────────│ +β”‚ customerId (PK) β”‚ +β”‚ name β”‚ +β”‚ email β”‚ +β”‚ ... β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ 1 + β”‚ + β”‚ creates + β”‚ + β”‚ * +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Appointment β”‚ * β”‚ Employee β”‚ +│─────────────────────│─────────│─────────────────────│ +β”‚ appointmentId (PK) β”‚ assignedβ”‚ employeeId (PK) β”‚ +β”‚ customerId (FK) β”‚ to β”‚ name β”‚ +β”‚ status │─────────│ isAvailable β”‚ +β”‚ assignedEmployeeId β”‚ 1 β”‚ specialization β”‚ +β”‚ description β”‚ β”‚ ... β”‚ +β”‚ appointmentDateTime β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ 1 + β”‚ 1 β”‚ + β”‚ β”‚ handles + β”‚ for β”‚ + β”‚ β”‚ * + β”‚ * β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Project β”‚ +β”‚ Vehicle β”‚ │─────────────────────│ +│─────────────────────│ * β”‚ projectId (PK) β”‚ +β”‚ vehicleId (PK) │─────────│ customerId (FK) β”‚ +β”‚ make β”‚ used in β”‚ status β”‚ +β”‚ model │─────────│ assignedEmployeeId β”‚ +β”‚ year β”‚ 1 β”‚ projectName β”‚ +β”‚ ... β”‚ β”‚ description β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +## Status Flow Diagrams + +### Appointment Status Flow + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ PENDING β”‚ ◄─── Customer creates appointment +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”‚ Admin assigns to employee + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ASSIGNED β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”‚ Employee confirms + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ CONFIRMED β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”‚ Work begins + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ IN_PROGRESS β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”‚ Work finished + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ COMPLETED β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +Alternative paths: +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚CANCELLEDβ”‚ ◄─── Can be cancelled anytime +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ NO_SHOW β”‚ ◄─── If customer doesn't show up +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +### Project Status Flow + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ PENDING β”‚ ◄─── Customer creates project +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”‚ Admin assigns to employee + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ASSIGNED β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”‚ Work begins + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ IN_PROGRESS │◄──┐ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ + β”‚ β”‚ Resume + β”‚ β”‚ + β”‚ Pause β”‚ + β–Ό β”‚ +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ ON_HOLD β”‚β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”‚ Work finished + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ COMPLETED β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +Alternative path: +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚CANCELLEDβ”‚ ◄─── Can be cancelled anytime +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +## File Structure + +``` +ead-automobile/ +β”‚ +β”œβ”€β”€ src/main/java/com/example/ead_backend/ +β”‚ β”‚ +β”‚ β”œβ”€β”€ controller/ +β”‚ β”‚ └── AdminController.java βœ… REST API endpoints +β”‚ β”‚ +β”‚ β”œβ”€β”€ service/ +β”‚ β”‚ β”œβ”€β”€ AdminService.java βœ… Service interface +β”‚ β”‚ └── impl/ +β”‚ β”‚ └── AdminServiceImpl.java βœ… Service implementation +β”‚ β”‚ +β”‚ β”œβ”€β”€ repository/ +β”‚ β”‚ β”œβ”€β”€ AppointmentRepository.java βœ… Appointment data access +β”‚ β”‚ β”œβ”€β”€ ProjectRepository.java βœ… Project data access +β”‚ β”‚ └── EmployeeRepository.java βœ… Employee data access +β”‚ β”‚ +β”‚ β”œβ”€β”€ model/ +β”‚ β”‚ β”œβ”€β”€ entity/ +β”‚ β”‚ β”‚ β”œβ”€β”€ Appointment.java βœ… Appointment entity +β”‚ β”‚ β”‚ β”œβ”€β”€ Project.java βœ… Project entity +β”‚ β”‚ β”‚ └── Employee.java βœ… Employee entity +β”‚ β”‚ β”‚ +β”‚ β”‚ └── enums/ +β”‚ β”‚ β”œβ”€β”€ AppointmentStatus.java βœ… Appointment statuses +β”‚ β”‚ └── ProjectStatus.java βœ… Project statuses +β”‚ β”‚ +β”‚ └── dto/ +β”‚ β”œβ”€β”€ AppointmentDTO.java βœ… Appointment DTO +β”‚ β”œβ”€β”€ ProjectDTO.java βœ… Project DTO +β”‚ └── EmployeeDTO.java βœ… Employee DTO +β”‚ +β”œβ”€β”€ IMPLEMENTATION_SUMMARY.md βœ… Implementation overview +β”œβ”€β”€ ADMIN_IMPLEMENTATION_GUIDE.md βœ… Detailed guide +β”œβ”€β”€ API_TEST_EXAMPLES.md βœ… API testing guide +β”œβ”€β”€ QUICK_START.md βœ… Quick setup guide +β”œβ”€β”€ ARCHITECTURE.md βœ… This file +└── test-data.sql βœ… Sample test data +``` + +--- + +**Architecture Pattern**: Layered Architecture (MVC + Service Layer) +- **Controller Layer**: Handles HTTP requests/responses +- **Service Layer**: Business logic and validation +- **Repository Layer**: Data access +- **Entity Layer**: Database models +- **DTO Layer**: Data transfer objects + +This architecture ensures: +- βœ… Separation of concerns +- βœ… Easy testing +- βœ… Maintainability +- βœ… Scalability diff --git a/IMPLEMENTATION_SUMMARY.md b/IMPLEMENTATION_SUMMARY.md new file mode 100644 index 0000000..cf31f19 --- /dev/null +++ b/IMPLEMENTATION_SUMMARY.md @@ -0,0 +1,179 @@ +# Implementation Summary - Admin Module + +## What Was Implemented + +This implementation provides the **admin functionality** for viewing and assigning appointments and projects to employees. + +## Files Modified/Created + +### 1. Entity Models (Updated) +- βœ… `model/entity/Appointment.java` - Added fields for customer, vehicle, status, assignment +- βœ… `model/entity/Project.java` - Added fields for customer, vehicle, status, assignment +- βœ… `model/entity/Employee.java` - Added fields for employee details and availability + +### 2. Enums (Updated) +- βœ… `model/enums/AppointmentStatus.java` - Defined status values (PENDING, ASSIGNED, etc.) +- βœ… `model/enums/ProjectStatus.java` - Defined status values (PENDING, ASSIGNED, etc.) + +### 3. DTOs (Updated) +- βœ… `dto/AppointmentDTO.java` - Data transfer object for appointments +- βœ… `dto/ProjectDTO.java` - Data transfer object for projects +- βœ… `dto/EmployeeDTO.java` - Data transfer object for employees + +### 4. Repositories (Updated) +- βœ… `repository/AppointmentRepository.java` - Added queries to find pending appointments +- βœ… `repository/ProjectRepository.java` - Added queries to find pending projects +- βœ… `repository/EmployeeRepository.java` - Added queries to find available employees + +### 5. Service Layer (Updated) +- βœ… `service/AdminService.java` - Interface with all admin operations +- βœ… `service/impl/AdminServiceImpl.java` - Full implementation with business logic + +### 6. Controller Layer (Updated) +- βœ… `controller/AdminController.java` - REST API endpoints for admin operations + +### 7. Documentation (Created) +- βœ… `ADMIN_IMPLEMENTATION_GUIDE.md` - Complete implementation guide +- βœ… `API_TEST_EXAMPLES.md` - API testing examples and sample requests + +## Key Features Implemented + +### 1. View Pending Appointments/Projects +- Admin can fetch all appointments/projects created by customers that are in PENDING status +- Endpoint: `GET /api/admin/appointments/pending` +- Endpoint: `GET /api/admin/projects/pending` + +### 2. View All Appointments/Projects +- Admin can view all appointments/projects regardless of status +- Endpoint: `GET /api/admin/appointments` +- Endpoint: `GET /api/admin/projects` + +### 3. View Available Employees +- Admin can see which employees are available for assignment +- Endpoint: `GET /api/admin/employees/available` +- Includes employee details like name, specialization, etc. + +### 4. Assign Appointments to Employees +- Admin can assign pending appointments to available employees +- Endpoint: `PUT /api/admin/appointments/{appointmentId}/assign/{employeeId}` +- Validates employee availability +- Updates appointment status to ASSIGNED + +### 5. Assign Projects to Employees +- Admin can assign pending projects to available employees +- Endpoint: `PUT /api/admin/projects/{projectId}/assign/{employeeId}` +- Validates employee availability +- Updates project status to ASSIGNED + +## API Endpoints Summary + +### Appointment Management +| Method | Endpoint | Description | +|--------|----------|-------------| +| GET | `/api/admin/appointments/pending` | Get all pending appointments | +| GET | `/api/admin/appointments` | Get all appointments | +| GET | `/api/admin/appointments/{id}` | Get appointment by ID | +| PUT | `/api/admin/appointments/{id}/assign/{empId}` | Assign to employee | + +### Project Management +| Method | Endpoint | Description | +|--------|----------|-------------| +| GET | `/api/admin/projects/pending` | Get all pending projects | +| GET | `/api/admin/projects` | Get all projects | +| GET | `/api/admin/projects/{id}` | Get project by ID | +| PUT | `/api/admin/projects/{id}/assign/{empId}` | Assign to employee | + +### Employee Management +| Method | Endpoint | Description | +|--------|----------|-------------| +| GET | `/api/admin/employees/available` | Get all available employees | +| GET | `/api/admin/employees` | Get all employees | +| GET | `/api/admin/employees/{id}` | Get employee by ID | + +## Integration Points + +### From Customer Module (Your Team Member's Part) +**What they need to do:** +1. Create appointments/projects with `status = PENDING` +2. Leave `assignedEmployeeId = null` +3. Set appropriate customer and vehicle IDs + +**What you consume:** +1. Fetch these pending items using repository methods +2. Display to admin +3. Allow admin to assign + +### To Employee Module (If Applicable) +**What employees receive:** +1. Appointments/Projects with `status = ASSIGNED` +2. Their ID in `assignedEmployeeId` field +3. Can query using `findByAssignedEmployeeId(employeeId)` + +## Business Logic Highlights + +### Assignment Validation +When admin assigns an appointment/project: +1. βœ… Checks if appointment/project exists +2. βœ… Checks if employee exists +3. βœ… Validates employee is available (`isAvailable = true`) +4. βœ… Updates status from PENDING to ASSIGNED +5. βœ… Sets assignedEmployeeId +6. βœ… Updates timestamp + +### Error Handling +- Returns 404 if appointment/project/employee not found +- Returns 400 if trying to assign to unavailable employee +- Returns 500 for unexpected errors + +## Data Flow + +``` +Customer Creates β†’ Status: PENDING β†’ Admin Views β†’ Admin Assigns β†’ Status: ASSIGNED β†’ Employee Handles +``` + +1. **Customer creates** appointment/project (implemented by your team member) +2. **Status set to PENDING**, no employee assigned +3. **Admin views** pending items via API +4. **Admin selects** available employee +5. **System assigns** and changes status to ASSIGNED +6. **Employee can now** see and work on the assignment + +## Testing Checklist + +- [ ] Database tables created (Appointments, Projects, Employees) +- [ ] Sample data inserted with PENDING status +- [ ] Can retrieve pending appointments: `GET /api/admin/appointments/pending` +- [ ] Can retrieve pending projects: `GET /api/admin/projects/pending` +- [ ] Can retrieve available employees: `GET /api/admin/employees/available` +- [ ] Can assign appointment to employee: `PUT /api/admin/appointments/{id}/assign/{empId}` +- [ ] Can assign project to employee: `PUT /api/admin/projects/{id}/assign/{empId}` +- [ ] Assignment changes status from PENDING to ASSIGNED +- [ ] Cannot assign to unavailable employee (returns error) +- [ ] Cannot assign non-existent appointment/project (returns 404) + +## Next Steps + +1. **Run the application**: `./mvnw spring-boot:run` (or `mvnw.cmd spring-boot:run` on Windows) +2. **Verify database**: Check if tables are created +3. **Insert test data**: Use SQL scripts from `API_TEST_EXAMPLES.md` +4. **Test endpoints**: Use Postman or cURL commands provided +5. **Integrate with frontend**: Connect your frontend to these APIs +6. **Coordinate with team**: Ensure customer module sets correct status + +## Notes + +- All endpoints return JSON +- CORS is enabled for all origins (`@CrossOrigin(origins = "*")`) +- Base URL: `/api/admin` +- Transactions are used for data consistency +- DTOs are used to avoid exposing entity internals + +## Support Files + +- **ADMIN_IMPLEMENTATION_GUIDE.md**: Detailed technical documentation +- **API_TEST_EXAMPLES.md**: API testing guide with examples +- **This file**: Quick summary of what was implemented + +--- + +**Status**: βœ… Implementation Complete - Ready for Testing and Integration diff --git a/src/main/java/com/example/ead_backend/controller/AdminController.java b/src/main/java/com/example/ead_backend/controller/AdminController.java index ba06233..91bb65c 100644 --- a/src/main/java/com/example/ead_backend/controller/AdminController.java +++ b/src/main/java/com/example/ead_backend/controller/AdminController.java @@ -1,5 +1,395 @@ package com.example.ead_backend.controller; -public class AdminController { +import com.example.ead_backend.dto.AppointmentDTO; +import com.example.ead_backend.dto.EmployeeDTO; +import com.example.ead_backend.dto.ProjectDTO; +import com.example.ead_backend.dto.TaskDTO; +import com.example.ead_backend.service.AdminService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +@RestController +@RequestMapping("/api/admin") +@CrossOrigin(origins = "*") +public class AdminController { + + @Autowired + private AdminService adminService; + + // ==================== Appointment Endpoints ==================== + + /** + * Get all pending appointments (created by customers, waiting for assignment) + */ + @GetMapping("/appointments/pending") + public ResponseEntity> getAllPendingAppointments() { + try { + List appointments = adminService.getAllPendingAppointments(); + return ResponseEntity.ok(appointments); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + /** + * Get all appointments + */ + @GetMapping("/appointments") + public ResponseEntity> getAllAppointments() { + try { + List appointments = adminService.getAllAppointments(); + return ResponseEntity.ok(appointments); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + /** + * Get appointment by ID + */ + @GetMapping("/appointments/{appointmentId}") + public ResponseEntity getAppointmentById(@PathVariable String appointmentId) { + try { + AppointmentDTO appointment = adminService.getAppointmentById(appointmentId); + return ResponseEntity.ok(appointment); + } catch (RuntimeException e) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + /** + * Assign appointment to an employee + */ + @PutMapping("/appointments/{appointmentId}/assign/{employeeId}") + public ResponseEntity assignAppointmentToEmployee( + @PathVariable String appointmentId, + @PathVariable String employeeId) { + try { + AppointmentDTO assignedAppointment = adminService.assignAppointmentToEmployee(appointmentId, employeeId); + return ResponseEntity.ok(assignedAppointment); + } catch (RuntimeException e) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + /** + * Create a new appointment + */ + @PostMapping("/appointments") + public ResponseEntity createAppointment(@RequestBody AppointmentDTO appointmentDTO) { + try { + AppointmentDTO createdAppointment = adminService.createAppointment(appointmentDTO); + return ResponseEntity.status(HttpStatus.CREATED).body(createdAppointment); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + /** + * Update an existing appointment + */ + @PutMapping("/appointments/{appointmentId}") + public ResponseEntity updateAppointment( + @PathVariable String appointmentId, + @RequestBody AppointmentDTO appointmentDTO) { + try { + AppointmentDTO updatedAppointment = adminService.updateAppointment(appointmentId, appointmentDTO); + return ResponseEntity.ok(updatedAppointment); + } catch (RuntimeException e) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + /** + * Delete an appointment + */ + @DeleteMapping("/appointments/{appointmentId}") + public ResponseEntity deleteAppointment(@PathVariable String appointmentId) { + try { + adminService.deleteAppointment(appointmentId); + return ResponseEntity.noContent().build(); + } catch (RuntimeException e) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + // ==================== Project Endpoints ==================== + + /** + * Get all pending projects (created by customers, waiting for assignment) + */ + @GetMapping("/projects/pending") + public ResponseEntity> getAllPendingProjects() { + try { + List projects = adminService.getAllPendingProjects(); + return ResponseEntity.ok(projects); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + /** + * Get all projects + */ + @GetMapping("/projects") + public ResponseEntity> getAllProjects() { + try { + List projects = adminService.getAllProjects(); + return ResponseEntity.ok(projects); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + /** + * Get project by ID + */ + @GetMapping("/projects/{projectId}") + public ResponseEntity getProjectById(@PathVariable String projectId) { + try { + ProjectDTO project = adminService.getProjectById(projectId); + return ResponseEntity.ok(project); + } catch (RuntimeException e) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + /** + * Assign project to an employee + */ + @PutMapping("/projects/{projectId}/assign/{employeeId}") + public ResponseEntity assignProjectToEmployee( + @PathVariable String projectId, + @PathVariable String employeeId) { + try { + ProjectDTO assignedProject = adminService.assignProjectToEmployee(projectId, employeeId); + return ResponseEntity.ok(assignedProject); + } catch (RuntimeException e) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + /** + * Create a new project + */ + @PostMapping("/projects") + public ResponseEntity createProject(@RequestBody ProjectDTO projectDTO) { + try { + ProjectDTO createdProject = adminService.createProject(projectDTO); + return ResponseEntity.status(HttpStatus.CREATED).body(createdProject); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + /** + * Update an existing project + */ + @PutMapping("/projects/{projectId}") + public ResponseEntity updateProject( + @PathVariable String projectId, + @RequestBody ProjectDTO projectDTO) { + try { + ProjectDTO updatedProject = adminService.updateProject(projectId, projectDTO); + return ResponseEntity.ok(updatedProject); + } catch (RuntimeException e) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + /** + * Delete a project + */ + @DeleteMapping("/projects/{projectId}") + public ResponseEntity deleteProject(@PathVariable String projectId) { + try { + adminService.deleteProject(projectId); + return ResponseEntity.noContent().build(); + } catch (RuntimeException e) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + // ==================== Task Endpoints ==================== + + /** + * Get all tasks for a specific appointment + */ + @GetMapping("/appointments/{appointmentId}/tasks") + public ResponseEntity> getAllTasksForAppointment(@PathVariable String appointmentId) { + try { + List tasks = adminService.getAllTasksForAppointment(appointmentId); + return ResponseEntity.ok(tasks); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + /** + * Get task by ID + */ + @GetMapping("/tasks/{taskId}") + public ResponseEntity getTaskById(@PathVariable String taskId) { + try { + TaskDTO task = adminService.getTaskById(taskId); + return ResponseEntity.ok(task); + } catch (RuntimeException e) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + /** + * Create a new task + */ + @PostMapping("/tasks") + public ResponseEntity createTask(@RequestBody TaskDTO taskDTO) { + try { + TaskDTO createdTask = adminService.createTask(taskDTO); + return ResponseEntity.status(HttpStatus.CREATED).body(createdTask); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + /** + * Update an existing task + */ + @PutMapping("/tasks/{taskId}") + public ResponseEntity updateTask( + @PathVariable String taskId, + @RequestBody TaskDTO taskDTO) { + try { + TaskDTO updatedTask = adminService.updateTask(taskId, taskDTO); + return ResponseEntity.ok(updatedTask); + } catch (RuntimeException e) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + /** + * Delete a task + */ + @DeleteMapping("/tasks/{taskId}") + public ResponseEntity deleteTask(@PathVariable String taskId) { + try { + adminService.deleteTask(taskId); + return ResponseEntity.noContent().build(); + } catch (RuntimeException e) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + // ==================== Employee Endpoints ==================== + + /** + * Get all available employees + */ + @GetMapping("/employees/available") + public ResponseEntity> getAllAvailableEmployees() { + try { + List employees = adminService.getAllAvailableEmployees(); + return ResponseEntity.ok(employees); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + /** + * Get all employees + */ + @GetMapping("/employees") + public ResponseEntity> getAllEmployees() { + try { + List employees = adminService.getAllEmployees(); + return ResponseEntity.ok(employees); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + /** + * Get employee by ID + */ + @GetMapping("/employees/{employeeId}") + public ResponseEntity getEmployeeById(@PathVariable String employeeId) { + try { + EmployeeDTO employee = adminService.getEmployeeById(employeeId); + return ResponseEntity.ok(employee); + } catch (RuntimeException e) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + /** + * Create a new employee + */ + @PostMapping("/employees") + public ResponseEntity createEmployee(@RequestBody EmployeeDTO employeeDTO) { + try { + EmployeeDTO createdEmployee = adminService.createEmployee(employeeDTO); + return ResponseEntity.status(HttpStatus.CREATED).body(createdEmployee); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + /** + * Update an existing employee + */ + @PutMapping("/employees/{employeeId}") + public ResponseEntity updateEmployee( + @PathVariable String employeeId, + @RequestBody EmployeeDTO employeeDTO) { + try { + EmployeeDTO updatedEmployee = adminService.updateEmployee(employeeId, employeeDTO); + return ResponseEntity.ok(updatedEmployee); + } catch (RuntimeException e) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + + /** + * Delete an employee + */ + @DeleteMapping("/employees/{employeeId}") + public ResponseEntity deleteEmployee(@PathVariable String employeeId) { + try { + adminService.deleteEmployee(employeeId); + return ResponseEntity.noContent().build(); + } catch (RuntimeException e) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } } diff --git a/src/main/java/com/example/ead_backend/dto/AppointmentDTO.java b/src/main/java/com/example/ead_backend/dto/AppointmentDTO.java index f30e215..7f5efb3 100644 --- a/src/main/java/com/example/ead_backend/dto/AppointmentDTO.java +++ b/src/main/java/com/example/ead_backend/dto/AppointmentDTO.java @@ -1,5 +1,24 @@ package com.example.ead_backend.dto; +import com.example.ead_backend.model.enums.AppointmentStatus; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@AllArgsConstructor public class AppointmentDTO { - + private String appointmentId; + private String customerId; + private String vehicleId; + private String description; + private LocalDateTime appointmentDateTime; + private AppointmentStatus status; + private String assignedEmployeeId; + private String assignedEmployeeName; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; } diff --git a/src/main/java/com/example/ead_backend/dto/EmployeeDTO.java b/src/main/java/com/example/ead_backend/dto/EmployeeDTO.java index c25f241..c26d40e 100644 --- a/src/main/java/com/example/ead_backend/dto/EmployeeDTO.java +++ b/src/main/java/com/example/ead_backend/dto/EmployeeDTO.java @@ -1,5 +1,21 @@ package com.example.ead_backend.dto; -public class EmployeeDTO { +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; +@Data +@NoArgsConstructor +@AllArgsConstructor +public class EmployeeDTO { + private String employeeId; + private String name; + private String email; + private String phone; + private String specialization; + private boolean isAvailable; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; } diff --git a/src/main/java/com/example/ead_backend/dto/ProjectDTO.java b/src/main/java/com/example/ead_backend/dto/ProjectDTO.java index 7df8817..8ad6044 100644 --- a/src/main/java/com/example/ead_backend/dto/ProjectDTO.java +++ b/src/main/java/com/example/ead_backend/dto/ProjectDTO.java @@ -1,5 +1,26 @@ package com.example.ead_backend.dto; -public class ProjectDTO { +import com.example.ead_backend.model.enums.ProjectStatus; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ProjectDTO { + private String projectId; + private String customerId; + private String vehicleId; + private String projectName; + private String description; + private LocalDateTime startDate; + private LocalDateTime expectedEndDate; + private ProjectStatus status; + private String assignedEmployeeId; + private String assignedEmployeeName; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; } diff --git a/src/main/java/com/example/ead_backend/dto/TaskDTO.java b/src/main/java/com/example/ead_backend/dto/TaskDTO.java index 8a67aae..f30c77a 100644 --- a/src/main/java/com/example/ead_backend/dto/TaskDTO.java +++ b/src/main/java/com/example/ead_backend/dto/TaskDTO.java @@ -1,5 +1,24 @@ package com.example.ead_backend.dto; +import com.example.ead_backend.model.enums.TaskStatus; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@AllArgsConstructor public class TaskDTO { - + private String taskId; + private String appointmentId; + private String taskName; + private String description; + private String assignedEmployeeId; + private String assignedEmployeeName; + private TaskStatus status; + private LocalDateTime dueDate; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; } diff --git a/src/main/java/com/example/ead_backend/model/entity/Appointment.java b/src/main/java/com/example/ead_backend/model/entity/Appointment.java index d8d21bd..6834bb0 100644 --- a/src/main/java/com/example/ead_backend/model/entity/Appointment.java +++ b/src/main/java/com/example/ead_backend/model/entity/Appointment.java @@ -1,7 +1,9 @@ package com.example.ead_backend.model.entity; +import com.example.ead_backend.model.enums.AppointmentStatus; import jakarta.persistence.*; import lombok.Data; +import java.time.LocalDateTime; @Entity @Table(name = "Appointments") @@ -9,4 +11,25 @@ public class Appointment { @Id private String appointmentId; + + private String customerId; + + private String vehicleId; + + private String description; + + private LocalDateTime appointmentDateTime; + + @Enumerated(EnumType.STRING) + private AppointmentStatus status = AppointmentStatus.PENDING; + + private String assignedEmployeeId; + + private LocalDateTime createdAt; + + private LocalDateTime updatedAt; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "assignedEmployeeId", insertable = false, updatable = false) + private Employee assignedEmployee; } diff --git a/src/main/java/com/example/ead_backend/model/entity/Employee.java b/src/main/java/com/example/ead_backend/model/entity/Employee.java index d310606..a109c1a 100644 --- a/src/main/java/com/example/ead_backend/model/entity/Employee.java +++ b/src/main/java/com/example/ead_backend/model/entity/Employee.java @@ -2,6 +2,8 @@ import jakarta.persistence.*; import lombok.Data; +import java.time.LocalDateTime; +import java.util.List; @Entity @Table(name = "Employees") @@ -9,4 +11,24 @@ public class Employee { @Id private String employeeId; + + private String name; + + private String email; + + private String phone; + + private String specialization; + + private boolean isAvailable = true; + + private LocalDateTime createdAt; + + private LocalDateTime updatedAt; + + @OneToMany(mappedBy = "assignedEmployee", fetch = FetchType.LAZY) + private List appointments; + + @OneToMany(mappedBy = "assignedEmployee", fetch = FetchType.LAZY) + private List projects; } diff --git a/src/main/java/com/example/ead_backend/model/entity/Project.java b/src/main/java/com/example/ead_backend/model/entity/Project.java index d8bee9c..5ccb96b 100644 --- a/src/main/java/com/example/ead_backend/model/entity/Project.java +++ b/src/main/java/com/example/ead_backend/model/entity/Project.java @@ -1,7 +1,9 @@ package com.example.ead_backend.model.entity; +import com.example.ead_backend.model.enums.ProjectStatus; import jakarta.persistence.*; import lombok.Data; +import java.time.LocalDateTime; @Entity @Table(name = "Projects") @@ -9,4 +11,29 @@ public class Project { @Id private String projectId; + + private String customerId; + + private String vehicleId; + + private String projectName; + + private String description; + + private LocalDateTime startDate; + + private LocalDateTime expectedEndDate; + + @Enumerated(EnumType.STRING) + private ProjectStatus status = ProjectStatus.PENDING; + + private String assignedEmployeeId; + + private LocalDateTime createdAt; + + private LocalDateTime updatedAt; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "assignedEmployeeId", insertable = false, updatable = false) + private Employee assignedEmployee; } diff --git a/src/main/java/com/example/ead_backend/model/entity/Task.java b/src/main/java/com/example/ead_backend/model/entity/Task.java index af7223e..e64abcd 100644 --- a/src/main/java/com/example/ead_backend/model/entity/Task.java +++ b/src/main/java/com/example/ead_backend/model/entity/Task.java @@ -1,7 +1,9 @@ package com.example.ead_backend.model.entity; +import com.example.ead_backend.model.enums.TaskStatus; import jakarta.persistence.*; import lombok.Data; +import java.time.LocalDateTime; @Entity @Table(name = "Tasks") @@ -9,4 +11,25 @@ public class Task { @Id private String taskId; + + private String appointmentId; + + private String taskName; + + private String description; + + private String assignedEmployeeId; + + @Enumerated(EnumType.STRING) + private TaskStatus status; + + private LocalDateTime dueDate; + + private LocalDateTime createdAt; + + private LocalDateTime updatedAt; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "appointmentId", insertable = false, updatable = false) + private Appointment appointment; } diff --git a/src/main/java/com/example/ead_backend/model/enums/AppointmentStatus.java b/src/main/java/com/example/ead_backend/model/enums/AppointmentStatus.java index e7a27e4..ad0c156 100644 --- a/src/main/java/com/example/ead_backend/model/enums/AppointmentStatus.java +++ b/src/main/java/com/example/ead_backend/model/enums/AppointmentStatus.java @@ -1,10 +1,11 @@ package com.example.ead_backend.model.enums; public enum AppointmentStatus { - // SCHEDULED, - // CONFIRMED, - // IN_PROGRESS, - // COMPLETED, - // CANCELLED, - // NO_SHOW + PENDING, // Created by customer, waiting for assignment + ASSIGNED, // Assigned to an employee by admin + CONFIRMED, // Employee confirmed the appointment + IN_PROGRESS, // Appointment is in progress + COMPLETED, // Appointment completed + CANCELLED, // Appointment cancelled + NO_SHOW // Customer didn't show up } diff --git a/src/main/java/com/example/ead_backend/model/enums/ProjectStatus.java b/src/main/java/com/example/ead_backend/model/enums/ProjectStatus.java index fa077e1..4074771 100644 --- a/src/main/java/com/example/ead_backend/model/enums/ProjectStatus.java +++ b/src/main/java/com/example/ead_backend/model/enums/ProjectStatus.java @@ -1,9 +1,10 @@ package com.example.ead_backend.model.enums; public enum ProjectStatus { - // PENDING, - // IN_PROGRESS, - // COMPLETED, - // CANCELLED, - // ON_HOLD + PENDING, // Created by customer, waiting for assignment + ASSIGNED, // Assigned to an employee by admin + IN_PROGRESS, // Project work in progress + COMPLETED, // Project completed + CANCELLED, // Project cancelled + ON_HOLD // Project temporarily on hold } diff --git a/src/main/java/com/example/ead_backend/model/enums/TaskStatus.java b/src/main/java/com/example/ead_backend/model/enums/TaskStatus.java index 9ee4e05..99ee7a8 100644 --- a/src/main/java/com/example/ead_backend/model/enums/TaskStatus.java +++ b/src/main/java/com/example/ead_backend/model/enums/TaskStatus.java @@ -1,8 +1,8 @@ package com.example.ead_backend.model.enums; public enum TaskStatus { - // TODO, - // IN_PROGRESS, - // COMPLETED, - // CANCELLED + TODO, // Task created, not started + IN_PROGRESS, // Task is being worked on + COMPLETED, // Task completed + CANCELLED // Task cancelled } diff --git a/src/main/java/com/example/ead_backend/repository/AppointmentRepository.java b/src/main/java/com/example/ead_backend/repository/AppointmentRepository.java index 5c59bbc..de2f605 100644 --- a/src/main/java/com/example/ead_backend/repository/AppointmentRepository.java +++ b/src/main/java/com/example/ead_backend/repository/AppointmentRepository.java @@ -1,10 +1,23 @@ package com.example.ead_backend.repository; import com.example.ead_backend.model.entity.Appointment; +import com.example.ead_backend.model.enums.AppointmentStatus; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface AppointmentRepository extends JpaRepository { + // Find all appointments with PENDING status (not yet assigned) + List findByStatus(AppointmentStatus status); + + // Find all appointments assigned to a specific employee + List findByAssignedEmployeeId(String employeeId); + + // Find all pending appointments (waiting for admin assignment) + @Query("SELECT a FROM Appointment a WHERE a.status = 'PENDING' OR a.assignedEmployeeId IS NULL") + List findAllPendingAppointments(); } diff --git a/src/main/java/com/example/ead_backend/repository/EmployeeRepository.java b/src/main/java/com/example/ead_backend/repository/EmployeeRepository.java index dd1113b..9442a9f 100644 --- a/src/main/java/com/example/ead_backend/repository/EmployeeRepository.java +++ b/src/main/java/com/example/ead_backend/repository/EmployeeRepository.java @@ -2,9 +2,21 @@ import com.example.ead_backend.model.entity.Employee; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface EmployeeRepository extends JpaRepository { - + + // Find all available employees + List findByIsAvailable(boolean isAvailable); + + // Find employees by specialization who are available + List findBySpecializationAndIsAvailable(String specialization, boolean isAvailable); + + // Get all available employees with their current workload + @Query("SELECT e FROM Employee e WHERE e.isAvailable = true") + List findAllAvailableEmployees(); } diff --git a/src/main/java/com/example/ead_backend/repository/ProjectRepository.java b/src/main/java/com/example/ead_backend/repository/ProjectRepository.java index 24df474..8497e98 100644 --- a/src/main/java/com/example/ead_backend/repository/ProjectRepository.java +++ b/src/main/java/com/example/ead_backend/repository/ProjectRepository.java @@ -1,10 +1,23 @@ package com.example.ead_backend.repository; import com.example.ead_backend.model.entity.Project; +import com.example.ead_backend.model.enums.ProjectStatus; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface ProjectRepository extends JpaRepository { + // Find all projects with PENDING status (not yet assigned) + List findByStatus(ProjectStatus status); + + // Find all projects assigned to a specific employee + List findByAssignedEmployeeId(String employeeId); + + // Find all pending projects (waiting for admin assignment) + @Query("SELECT p FROM Project p WHERE p.status = 'PENDING' OR p.assignedEmployeeId IS NULL") + List findAllPendingProjects(); } diff --git a/src/main/java/com/example/ead_backend/repository/TaskRepository.java b/src/main/java/com/example/ead_backend/repository/TaskRepository.java index 5cea183..dbc0b41 100644 --- a/src/main/java/com/example/ead_backend/repository/TaskRepository.java +++ b/src/main/java/com/example/ead_backend/repository/TaskRepository.java @@ -4,7 +4,17 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface TaskRepository extends JpaRepository { + // Find all tasks for a specific appointment + List findByAppointmentId(String appointmentId); + + // Find tasks by status + List findByStatus(String status); + + // Find tasks assigned to a specific employee + List findByAssignedEmployeeId(String employeeId); } diff --git a/src/main/java/com/example/ead_backend/service/AdminService.java b/src/main/java/com/example/ead_backend/service/AdminService.java index 0565ceb..b3143a3 100644 --- a/src/main/java/com/example/ead_backend/service/AdminService.java +++ b/src/main/java/com/example/ead_backend/service/AdminService.java @@ -1,6 +1,44 @@ package com.example.ead_backend.service; +import com.example.ead_backend.dto.AppointmentDTO; +import com.example.ead_backend.dto.EmployeeDTO; +import com.example.ead_backend.dto.ProjectDTO; +import com.example.ead_backend.dto.TaskDTO; -public interface AdminService { +import java.util.List; +public interface AdminService { + + // ==================== Appointment Management ==================== + List getAllPendingAppointments(); + List getAllAppointments(); + AppointmentDTO getAppointmentById(String appointmentId); + AppointmentDTO assignAppointmentToEmployee(String appointmentId, String employeeId); + AppointmentDTO createAppointment(AppointmentDTO appointmentDTO); + AppointmentDTO updateAppointment(String appointmentId, AppointmentDTO appointmentDTO); + void deleteAppointment(String appointmentId); + + // ==================== Project Management ==================== + List getAllPendingProjects(); + List getAllProjects(); + ProjectDTO getProjectById(String projectId); + ProjectDTO assignProjectToEmployee(String projectId, String employeeId); + ProjectDTO createProject(ProjectDTO projectDTO); + ProjectDTO updateProject(String projectId, ProjectDTO projectDTO); + void deleteProject(String projectId); + + // ==================== Task Management ==================== + List getAllTasksForAppointment(String appointmentId); + TaskDTO getTaskById(String taskId); + TaskDTO createTask(TaskDTO taskDTO); + TaskDTO updateTask(String taskId, TaskDTO taskDTO); + void deleteTask(String taskId); + + // ==================== Employee Management ==================== + List getAllAvailableEmployees(); + List getAllEmployees(); + EmployeeDTO getEmployeeById(String employeeId); + EmployeeDTO createEmployee(EmployeeDTO employeeDTO); + EmployeeDTO updateEmployee(String employeeId, EmployeeDTO employeeDTO); + void deleteEmployee(String employeeId); } diff --git a/src/main/java/com/example/ead_backend/service/impl/AdminServiceImpl.java b/src/main/java/com/example/ead_backend/service/impl/AdminServiceImpl.java index 83979d9..925d7dd 100644 --- a/src/main/java/com/example/ead_backend/service/impl/AdminServiceImpl.java +++ b/src/main/java/com/example/ead_backend/service/impl/AdminServiceImpl.java @@ -1,8 +1,449 @@ package com.example.ead_backend.service.impl; +import com.example.ead_backend.dto.AppointmentDTO; +import com.example.ead_backend.dto.EmployeeDTO; +import com.example.ead_backend.dto.ProjectDTO; +import com.example.ead_backend.dto.TaskDTO; +import com.example.ead_backend.model.entity.Appointment; +import com.example.ead_backend.model.entity.Employee; +import com.example.ead_backend.model.entity.Project; +import com.example.ead_backend.model.entity.Task; +import com.example.ead_backend.model.enums.AppointmentStatus; +import com.example.ead_backend.model.enums.ProjectStatus; +import com.example.ead_backend.repository.AppointmentRepository; +import com.example.ead_backend.repository.EmployeeRepository; +import com.example.ead_backend.repository.ProjectRepository; +import com.example.ead_backend.repository.TaskRepository; import com.example.ead_backend.service.AdminService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDateTime; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; +@Service public class AdminServiceImpl implements AdminService { - + + @Autowired + private AppointmentRepository appointmentRepository; + + @Autowired + private ProjectRepository projectRepository; + + @Autowired + private EmployeeRepository employeeRepository; + + @Autowired + private TaskRepository taskRepository; + + // ==================== Appointment Management ==================== + + @Override + public List getAllPendingAppointments() { + List appointments = appointmentRepository.findAllPendingAppointments(); + return appointments.stream() + .map(this::convertAppointmentToDTO) + .collect(Collectors.toList()); + } + + @Override + public List getAllAppointments() { + List appointments = appointmentRepository.findAll(); + return appointments.stream() + .map(this::convertAppointmentToDTO) + .collect(Collectors.toList()); + } + + @Override + public AppointmentDTO getAppointmentById(String appointmentId) { + Appointment appointment = appointmentRepository.findById(appointmentId) + .orElseThrow(() -> new RuntimeException("Appointment not found with id: " + appointmentId)); + return convertAppointmentToDTO(appointment); + } + + @Override + @Transactional + public AppointmentDTO assignAppointmentToEmployee(String appointmentId, String employeeId) { + // Fetch appointment + Appointment appointment = appointmentRepository.findById(appointmentId) + .orElseThrow(() -> new RuntimeException("Appointment not found with id: " + appointmentId)); + + // Fetch employee + Employee employee = employeeRepository.findById(employeeId) + .orElseThrow(() -> new RuntimeException("Employee not found with id: " + employeeId)); + + // Check if employee is available + if (!employee.isAvailable()) { + throw new RuntimeException("Employee is not available for assignment"); + } + + // Assign appointment to employee + appointment.setAssignedEmployeeId(employeeId); + appointment.setStatus(AppointmentStatus.ASSIGNED); + appointment.setUpdatedAt(LocalDateTime.now()); + + Appointment savedAppointment = appointmentRepository.save(appointment); + return convertAppointmentToDTO(savedAppointment); + } + + // ==================== Project Management ==================== + + @Override + public List getAllPendingProjects() { + List projects = projectRepository.findAllPendingProjects(); + return projects.stream() + .map(this::convertProjectToDTO) + .collect(Collectors.toList()); + } + + @Override + public List getAllProjects() { + List projects = projectRepository.findAll(); + return projects.stream() + .map(this::convertProjectToDTO) + .collect(Collectors.toList()); + } + + @Override + public ProjectDTO getProjectById(String projectId) { + Project project = projectRepository.findById(projectId) + .orElseThrow(() -> new RuntimeException("Project not found with id: " + projectId)); + return convertProjectToDTO(project); + } + + @Override + @Transactional + public ProjectDTO assignProjectToEmployee(String projectId, String employeeId) { + // Fetch project + Project project = projectRepository.findById(projectId) + .orElseThrow(() -> new RuntimeException("Project not found with id: " + projectId)); + + // Fetch employee + Employee employee = employeeRepository.findById(employeeId) + .orElseThrow(() -> new RuntimeException("Employee not found with id: " + employeeId)); + + // Check if employee is available + if (!employee.isAvailable()) { + throw new RuntimeException("Employee is not available for assignment"); + } + + // Assign project to employee + project.setAssignedEmployeeId(employeeId); + project.setStatus(ProjectStatus.ASSIGNED); + project.setUpdatedAt(LocalDateTime.now()); + + Project savedProject = projectRepository.save(project); + return convertProjectToDTO(savedProject); + } + + // ==================== Employee Management ==================== + + @Override + public List getAllAvailableEmployees() { + List employees = employeeRepository.findAllAvailableEmployees(); + return employees.stream() + .map(this::convertEmployeeToDTO) + .collect(Collectors.toList()); + } + + @Override + public List getAllEmployees() { + List employees = employeeRepository.findAll(); + return employees.stream() + .map(this::convertEmployeeToDTO) + .collect(Collectors.toList()); + } + + @Override + public EmployeeDTO getEmployeeById(String employeeId) { + Employee employee = employeeRepository.findById(employeeId) + .orElseThrow(() -> new RuntimeException("Employee not found with id: " + employeeId)); + return convertEmployeeToDTO(employee); + } + + // ==================== NEW CRUD Operations ==================== + + // Appointment CRUD + @Override + @Transactional + public AppointmentDTO createAppointment(AppointmentDTO appointmentDTO) { + Appointment appointment = new Appointment(); + appointment.setAppointmentId(UUID.randomUUID().toString()); + appointment.setCustomerId(appointmentDTO.getCustomerId()); + appointment.setVehicleId(appointmentDTO.getVehicleId()); + appointment.setDescription(appointmentDTO.getDescription()); + appointment.setAppointmentDateTime(appointmentDTO.getAppointmentDateTime()); + appointment.setStatus(appointmentDTO.getStatus() != null ? appointmentDTO.getStatus() : AppointmentStatus.PENDING); + appointment.setAssignedEmployeeId(appointmentDTO.getAssignedEmployeeId()); + appointment.setCreatedAt(LocalDateTime.now()); + appointment.setUpdatedAt(LocalDateTime.now()); + + Appointment savedAppointment = appointmentRepository.save(appointment); + return convertAppointmentToDTO(savedAppointment); + } + + @Override + @Transactional + public AppointmentDTO updateAppointment(String appointmentId, AppointmentDTO appointmentDTO) { + Appointment appointment = appointmentRepository.findById(appointmentId) + .orElseThrow(() -> new RuntimeException("Appointment not found with id: " + appointmentId)); + + if (appointmentDTO.getCustomerId() != null) appointment.setCustomerId(appointmentDTO.getCustomerId()); + if (appointmentDTO.getVehicleId() != null) appointment.setVehicleId(appointmentDTO.getVehicleId()); + if (appointmentDTO.getDescription() != null) appointment.setDescription(appointmentDTO.getDescription()); + if (appointmentDTO.getAppointmentDateTime() != null) appointment.setAppointmentDateTime(appointmentDTO.getAppointmentDateTime()); + if (appointmentDTO.getStatus() != null) appointment.setStatus(appointmentDTO.getStatus()); + if (appointmentDTO.getAssignedEmployeeId() != null) appointment.setAssignedEmployeeId(appointmentDTO.getAssignedEmployeeId()); + appointment.setUpdatedAt(LocalDateTime.now()); + + Appointment updatedAppointment = appointmentRepository.save(appointment); + return convertAppointmentToDTO(updatedAppointment); + } + + @Override + @Transactional + public void deleteAppointment(String appointmentId) { + if (!appointmentRepository.existsById(appointmentId)) { + throw new RuntimeException("Appointment not found with id: " + appointmentId); + } + appointmentRepository.deleteById(appointmentId); + } + + // Project CRUD + @Override + @Transactional + public ProjectDTO createProject(ProjectDTO projectDTO) { + Project project = new Project(); + project.setProjectId(UUID.randomUUID().toString()); + project.setCustomerId(projectDTO.getCustomerId()); + project.setVehicleId(projectDTO.getVehicleId()); + project.setProjectName(projectDTO.getProjectName()); + project.setDescription(projectDTO.getDescription()); + project.setStartDate(projectDTO.getStartDate()); + project.setExpectedEndDate(projectDTO.getExpectedEndDate()); + project.setStatus(projectDTO.getStatus() != null ? projectDTO.getStatus() : ProjectStatus.PENDING); + project.setAssignedEmployeeId(projectDTO.getAssignedEmployeeId()); + project.setCreatedAt(LocalDateTime.now()); + project.setUpdatedAt(LocalDateTime.now()); + + Project savedProject = projectRepository.save(project); + return convertProjectToDTO(savedProject); + } + + @Override + @Transactional + public ProjectDTO updateProject(String projectId, ProjectDTO projectDTO) { + Project project = projectRepository.findById(projectId) + .orElseThrow(() -> new RuntimeException("Project not found with id: " + projectId)); + + if (projectDTO.getCustomerId() != null) project.setCustomerId(projectDTO.getCustomerId()); + if (projectDTO.getVehicleId() != null) project.setVehicleId(projectDTO.getVehicleId()); + if (projectDTO.getProjectName() != null) project.setProjectName(projectDTO.getProjectName()); + if (projectDTO.getDescription() != null) project.setDescription(projectDTO.getDescription()); + if (projectDTO.getStartDate() != null) project.setStartDate(projectDTO.getStartDate()); + if (projectDTO.getExpectedEndDate() != null) project.setExpectedEndDate(projectDTO.getExpectedEndDate()); + if (projectDTO.getStatus() != null) project.setStatus(projectDTO.getStatus()); + if (projectDTO.getAssignedEmployeeId() != null) project.setAssignedEmployeeId(projectDTO.getAssignedEmployeeId()); + project.setUpdatedAt(LocalDateTime.now()); + + Project updatedProject = projectRepository.save(project); + return convertProjectToDTO(updatedProject); + } + + @Override + @Transactional + public void deleteProject(String projectId) { + if (!projectRepository.existsById(projectId)) { + throw new RuntimeException("Project not found with id: " + projectId); + } + projectRepository.deleteById(projectId); + } + + // Task CRUD + @Override + public List getAllTasksForAppointment(String appointmentId) { + List tasks = taskRepository.findByAppointmentId(appointmentId); + return tasks.stream() + .map(this::convertTaskToDTO) + .collect(Collectors.toList()); + } + + @Override + public TaskDTO getTaskById(String taskId) { + Task task = taskRepository.findById(taskId) + .orElseThrow(() -> new RuntimeException("Task not found with id: " + taskId)); + return convertTaskToDTO(task); + } + + @Override + @Transactional + public TaskDTO createTask(TaskDTO taskDTO) { + Task task = new Task(); + task.setTaskId(UUID.randomUUID().toString()); + task.setAppointmentId(taskDTO.getAppointmentId()); + task.setTaskName(taskDTO.getTaskName()); + task.setDescription(taskDTO.getDescription()); + task.setAssignedEmployeeId(taskDTO.getAssignedEmployeeId()); + task.setStatus(taskDTO.getStatus()); + task.setDueDate(taskDTO.getDueDate()); + task.setCreatedAt(LocalDateTime.now()); + task.setUpdatedAt(LocalDateTime.now()); + + Task savedTask = taskRepository.save(task); + return convertTaskToDTO(savedTask); + } + + @Override + @Transactional + public TaskDTO updateTask(String taskId, TaskDTO taskDTO) { + Task task = taskRepository.findById(taskId) + .orElseThrow(() -> new RuntimeException("Task not found with id: " + taskId)); + + if (taskDTO.getAppointmentId() != null) task.setAppointmentId(taskDTO.getAppointmentId()); + if (taskDTO.getTaskName() != null) task.setTaskName(taskDTO.getTaskName()); + if (taskDTO.getDescription() != null) task.setDescription(taskDTO.getDescription()); + if (taskDTO.getAssignedEmployeeId() != null) task.setAssignedEmployeeId(taskDTO.getAssignedEmployeeId()); + if (taskDTO.getStatus() != null) task.setStatus(taskDTO.getStatus()); + if (taskDTO.getDueDate() != null) task.setDueDate(taskDTO.getDueDate()); + task.setUpdatedAt(LocalDateTime.now()); + + Task updatedTask = taskRepository.save(task); + return convertTaskToDTO(updatedTask); + } + + @Override + @Transactional + public void deleteTask(String taskId) { + if (!taskRepository.existsById(taskId)) { + throw new RuntimeException("Task not found with id: " + taskId); + } + taskRepository.deleteById(taskId); + } + + // Employee CRUD + @Override + @Transactional + public EmployeeDTO createEmployee(EmployeeDTO employeeDTO) { + Employee employee = new Employee(); + employee.setEmployeeId(UUID.randomUUID().toString()); + employee.setName(employeeDTO.getName()); + employee.setEmail(employeeDTO.getEmail()); + employee.setPhone(employeeDTO.getPhone()); + employee.setSpecialization(employeeDTO.getSpecialization()); + employee.setAvailable(employeeDTO.isAvailable()); + employee.setCreatedAt(LocalDateTime.now()); + employee.setUpdatedAt(LocalDateTime.now()); + + Employee savedEmployee = employeeRepository.save(employee); + return convertEmployeeToDTO(savedEmployee); + } + + @Override + @Transactional + public EmployeeDTO updateEmployee(String employeeId, EmployeeDTO employeeDTO) { + Employee employee = employeeRepository.findById(employeeId) + .orElseThrow(() -> new RuntimeException("Employee not found with id: " + employeeId)); + + if (employeeDTO.getName() != null) employee.setName(employeeDTO.getName()); + if (employeeDTO.getEmail() != null) employee.setEmail(employeeDTO.getEmail()); + if (employeeDTO.getPhone() != null) employee.setPhone(employeeDTO.getPhone()); + if (employeeDTO.getSpecialization() != null) employee.setSpecialization(employeeDTO.getSpecialization()); + employee.setAvailable(employeeDTO.isAvailable()); + employee.setUpdatedAt(LocalDateTime.now()); + + Employee updatedEmployee = employeeRepository.save(employee); + return convertEmployeeToDTO(updatedEmployee); + } + + @Override + @Transactional + public void deleteEmployee(String employeeId) { + if (!employeeRepository.existsById(employeeId)) { + throw new RuntimeException("Employee not found with id: " + employeeId); + } + employeeRepository.deleteById(employeeId); + } + + // ==================== Helper Methods (DTO Converters) ==================== + + private AppointmentDTO convertAppointmentToDTO(Appointment appointment) { + AppointmentDTO dto = new AppointmentDTO(); + dto.setAppointmentId(appointment.getAppointmentId()); + dto.setCustomerId(appointment.getCustomerId()); + dto.setVehicleId(appointment.getVehicleId()); + dto.setDescription(appointment.getDescription()); + dto.setAppointmentDateTime(appointment.getAppointmentDateTime()); + dto.setStatus(appointment.getStatus()); + dto.setAssignedEmployeeId(appointment.getAssignedEmployeeId()); + + // Set assigned employee name if available + if (appointment.getAssignedEmployeeId() != null) { + employeeRepository.findById(appointment.getAssignedEmployeeId()) + .ifPresent(emp -> dto.setAssignedEmployeeName(emp.getName())); + } + + dto.setCreatedAt(appointment.getCreatedAt()); + dto.setUpdatedAt(appointment.getUpdatedAt()); + return dto; + } + + private ProjectDTO convertProjectToDTO(Project project) { + ProjectDTO dto = new ProjectDTO(); + dto.setProjectId(project.getProjectId()); + dto.setCustomerId(project.getCustomerId()); + dto.setVehicleId(project.getVehicleId()); + dto.setProjectName(project.getProjectName()); + dto.setDescription(project.getDescription()); + dto.setStartDate(project.getStartDate()); + dto.setExpectedEndDate(project.getExpectedEndDate()); + dto.setStatus(project.getStatus()); + dto.setAssignedEmployeeId(project.getAssignedEmployeeId()); + + // Set assigned employee name if available + if (project.getAssignedEmployeeId() != null) { + employeeRepository.findById(project.getAssignedEmployeeId()) + .ifPresent(emp -> dto.setAssignedEmployeeName(emp.getName())); + } + + dto.setCreatedAt(project.getCreatedAt()); + dto.setUpdatedAt(project.getUpdatedAt()); + return dto; + } + + private EmployeeDTO convertEmployeeToDTO(Employee employee) { + EmployeeDTO dto = new EmployeeDTO(); + dto.setEmployeeId(employee.getEmployeeId()); + dto.setName(employee.getName()); + dto.setEmail(employee.getEmail()); + dto.setPhone(employee.getPhone()); + dto.setSpecialization(employee.getSpecialization()); + dto.setAvailable(employee.isAvailable()); + dto.setCreatedAt(employee.getCreatedAt()); + dto.setUpdatedAt(employee.getUpdatedAt()); + return dto; + } + + private TaskDTO convertTaskToDTO(Task task) { + TaskDTO dto = new TaskDTO(); + dto.setTaskId(task.getTaskId()); + dto.setAppointmentId(task.getAppointmentId()); + dto.setTaskName(task.getTaskName()); + dto.setDescription(task.getDescription()); + dto.setAssignedEmployeeId(task.getAssignedEmployeeId()); + + // Set assigned employee name if available + if (task.getAssignedEmployeeId() != null) { + employeeRepository.findById(task.getAssignedEmployeeId()) + .ifPresent(emp -> dto.setAssignedEmployeeName(emp.getName())); + } + + dto.setStatus(task.getStatus()); + dto.setDueDate(task.getDueDate()); + dto.setCreatedAt(task.getCreatedAt()); + dto.setUpdatedAt(task.getUpdatedAt()); + return dto; + } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 8b9983a..7be2e6c 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,9 +1,9 @@ spring.application.name=ead-backend # PostgreSQL Database Configuration -spring.datasource.url=jdbc:postgresql://localhost:5432/ead_automobile +spring.datasource.url=jdbc:postgresql://localhost:5432/ead_automobilen spring.datasource.username=postgres -spring.datasource.password=pulina123 +spring.datasource.password=dila2001 spring.datasource.driver-class-name=org.postgresql.Driver # JPA/Hibernate Configuration diff --git a/test-data.sql b/test-data.sql new file mode 100644 index 0000000..56fc158 --- /dev/null +++ b/test-data.sql @@ -0,0 +1,174 @@ +-- Sample Test Data for Admin Module Testing +-- This script provides initial test data for the EAD Automobile System + +-- ===================================================== +-- 0. CLEAN UP EXISTING DATA (Optional - comment out if not needed) +-- ===================================================== +-- DELETE FROM tasks; +-- DELETE FROM appointments; +-- DELETE FROM projects; +-- DELETE FROM employees; +-- DELETE FROM vehicles; +-- DELETE FROM customers; + +-- ===================================================== +-- 1. INSERT SAMPLE CUSTOMERS +-- ===================================================== +INSERT INTO customers (customer_id) +VALUES + ('CUST001'), + ('CUST002'), + ('CUST003'), + ('CUST004'), + ('CUST005'), + ('CUST006'), + ('CUST007'), + ('CUST008') +ON CONFLICT (customer_id) DO NOTHING; + +-- ===================================================== +-- 2. INSERT SAMPLE VEHICLES +-- ===================================================== +INSERT INTO vehicles (vehicle_id) +VALUES + ('VEH001'), + ('VEH002'), + ('VEH003'), + ('VEH004'), + ('VEH005'), + ('VEH006'), + ('VEH007'), + ('VEH008') +ON CONFLICT (vehicle_id) DO NOTHING; + +-- ===================================================== +-- 3. INSERT SAMPLE EMPLOYEES +-- ===================================================== +INSERT INTO employees (employee_id, name, email, phone, specialization, is_available, created_at, updated_at) +VALUES + ('EMP001', 'John Doe', 'john.doe@automobile.com', '+1-555-0101', 'Engine Specialist', true, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + ('EMP002', 'Jane Smith', 'jane.smith@automobile.com', '+1-555-0102', 'Electrical Systems', true, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + ('EMP003', 'Mike Johnson', 'mike.johnson@automobile.com', '+1-555-0103', 'Body Work & Paint', true, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + ('EMP004', 'Sarah Williams', 'sarah.williams@automobile.com', '+1-555-0104', 'Transmission Expert', true, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + ('EMP005', 'David Brown', 'david.brown@automobile.com', '+1-555-0105', 'Brake Systems', false, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) +ON CONFLICT (employee_id) DO NOTHING; + +-- ===================================================== +-- 4. INSERT SAMPLE APPOINTMENTS (PENDING - Created by Customers) +-- ===================================================== +-- These appointments are waiting for admin to assign to employees + +INSERT INTO appointments (appointment_id, customer_id, vehicle_id, description, appointment_date_time, status, assigned_employee_id, created_at, updated_at) +VALUES + ('APT001', 'CUST001', 'VEH001', 'Regular oil change and filter replacement', '2025-11-10 10:00:00', 'PENDING', NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + ('APT002', 'CUST002', 'VEH002', 'Brake inspection and service', '2025-11-11 14:00:00', 'PENDING', NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + ('APT003', 'CUST003', 'VEH003', 'Engine diagnostic check - strange noise', '2025-11-12 09:00:00', 'PENDING', NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + ('APT004', 'CUST001', 'VEH001', 'Tire rotation and alignment', '2025-11-13 11:00:00', 'PENDING', NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + ('APT005', 'CUST004', 'VEH004', 'Air conditioning not working', '2025-11-15 15:00:00', 'PENDING', NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) +ON CONFLICT (appointment_id) DO NOTHING; + +-- ===================================================== +-- 5. INSERT SAMPLE PROJECTS (PENDING - Created by Customers) +-- ===================================================== +-- These projects are waiting for admin to assign to employees + +INSERT INTO projects (project_id, customer_id, vehicle_id, project_name, description, start_date, expected_end_date, status, assigned_employee_id, created_at, updated_at) +VALUES + ('PRJ001', 'CUST001', 'VEH001', 'Complete Engine Overhaul', 'Full engine teardown, inspection, and rebuild with new gaskets and seals', '2025-11-15 08:00:00', '2025-11-22 17:00:00', 'PENDING', NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + ('PRJ002', 'CUST003', 'VEH003', 'Full Body Paint & Restoration', 'Complete body paint job with rust removal and minor dent repair', '2025-11-18 09:00:00', '2025-11-25 16:00:00', 'PENDING', NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + ('PRJ003', 'CUST005', 'VEH005', 'Transmission Rebuild', 'Complete transmission overhaul with torque converter replacement', '2025-11-20 08:00:00', '2025-11-27 17:00:00', 'PENDING', NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + ('PRJ004', 'CUST002', 'VEH002', 'Suspension Upgrade', 'Install performance suspension kit with new shocks and springs', '2025-11-16 10:00:00', '2025-11-18 15:00:00', 'PENDING', NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) +ON CONFLICT (project_id) DO NOTHING; + +-- ===================================================== +-- 6. INSERT SOME ASSIGNED APPOINTMENTS (for testing view all) +-- ===================================================== + +INSERT INTO appointments (appointment_id, customer_id, vehicle_id, description, appointment_date_time, status, assigned_employee_id, created_at, updated_at) +VALUES + ('APT006', 'CUST006', 'VEH006', 'Battery replacement', '2025-11-08 10:00:00', 'ASSIGNED', 'EMP002', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + ('APT007', 'CUST007', 'VEH007', 'Windshield wiper replacement', '2025-11-09 13:00:00', 'COMPLETED', 'EMP003', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) +ON CONFLICT (appointment_id) DO NOTHING; + +-- ===================================================== +-- 7. INSERT SOME ASSIGNED PROJECTS (for testing view all) +-- ===================================================== + +INSERT INTO projects (project_id, customer_id, vehicle_id, project_name, description, start_date, expected_end_date, status, assigned_employee_id, created_at, updated_at) +VALUES + ('PRJ005', 'CUST006', 'VEH006', 'Custom Exhaust System', 'Install custom performance exhaust system', '2025-11-10 08:00:00', '2025-11-12 17:00:00', 'ASSIGNED', 'EMP001', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + ('PRJ006', 'CUST008', 'VEH008', 'Interior Detailing', 'Complete interior deep clean and detailing', '2025-11-05 09:00:00', '2025-11-06 15:00:00', 'COMPLETED', 'EMP003', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) +ON CONFLICT (project_id) DO NOTHING; + +-- ===================================================== +-- 8. INSERT SAMPLE TASKS FOR APPOINTMENTS +-- ===================================================== + +INSERT INTO tasks (task_id, appointment_id, task_name, description, assigned_employee_id, status, due_date, created_at, updated_at) +VALUES + ('TASK001', 'APT001', 'Drain old oil', 'Remove oil drain plug and drain old oil', 'EMP001', 'TODO', '2025-11-10 10:30:00', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + ('TASK002', 'APT001', 'Replace oil filter', 'Remove old filter and install new one', 'EMP001', 'TODO', '2025-11-10 10:45:00', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + ('TASK003', 'APT001', 'Add new oil', 'Fill with specified amount of new oil', 'EMP001', 'TODO', '2025-11-10 11:00:00', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + ('TASK004', 'APT002', 'Inspect brake pads', 'Check front and rear brake pad thickness', NULL, 'TODO', '2025-11-11 14:30:00', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + ('TASK005', 'APT002', 'Check brake fluid', 'Inspect brake fluid level and condition', NULL, 'TODO', '2025-11-11 15:00:00', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) +ON CONFLICT (task_id) DO NOTHING; + +-- ===================================================== +-- VERIFICATION QUERIES +-- ===================================================== + +-- Check employees +SELECT * FROM employees ORDER BY employee_id; + +-- Check pending appointments (should be visible to admin) +SELECT * FROM appointments WHERE status = 'PENDING' ORDER BY appointment_date_time; + +-- Check pending projects (should be visible to admin) +SELECT * FROM projects WHERE status = 'PENDING' ORDER BY start_date; + +-- Check all appointments +SELECT * FROM appointments ORDER BY appointment_id; + +-- Check all projects +SELECT * FROM projects ORDER BY project_id; + +-- Check available employees +SELECT * FROM employees WHERE is_available = true; + +-- ===================================================== +-- CLEANUP SCRIPT (Use if you need to reset data) +-- ===================================================== + +-- Uncomment below to delete all test data +/* +DELETE FROM appointments WHERE appointment_id LIKE 'APT%'; +DELETE FROM projects WHERE project_id LIKE 'PRJ%'; +DELETE FROM employees WHERE employee_id LIKE 'EMP%'; +*/ + +-- ===================================================== +-- NOTES +-- ===================================================== + +-- 1. Make sure customers and vehicles exist before inserting appointments/projects +-- or adjust the CUSTOMER_ID and VEHICLE_ID fields to match your data + +-- 2. The appointment_date_time and start_date/expected_end_date are set to future dates +-- Adjust as needed for your testing + +-- 3. Employee specializations: +-- - Engine Specialist: For engine-related work +-- - Electrical Systems: For electrical issues +-- - Body Work & Paint: For body and paint jobs +-- - Transmission Expert: For transmission work +-- - Brake Systems: For brake-related work + +-- 4. Status values: +-- Appointments: PENDING, ASSIGNED, CONFIRMED, IN_PROGRESS, COMPLETED, CANCELLED, NO_SHOW +-- Projects: PENDING, ASSIGNED, IN_PROGRESS, COMPLETED, CANCELLED, ON_HOLD + +-- 5. To test the admin functionality: +-- a. Use GET endpoints to view pending appointments/projects +-- b. Use GET endpoints to view available employees +-- c. Use PUT endpoints to assign appointments/projects to employees +-- d. Verify status changes from PENDING to ASSIGNED From 56e85156ed55a7e3d118af172c1e5ea55089b9ce Mon Sep 17 00:00:00 2001 From: nilangadilhara Date: Tue, 4 Nov 2025 19:29:40 +0530 Subject: [PATCH 2/2] Update database configuration in application.properties - Fixed database URL to ead_automobile - Cleared password field for security --- src/main/resources/application.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 7be2e6c..50d5200 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,9 +1,9 @@ spring.application.name=ead-backend # PostgreSQL Database Configuration -spring.datasource.url=jdbc:postgresql://localhost:5432/ead_automobilen +spring.datasource.url=jdbc:postgresql://localhost:5432/ead_automobile spring.datasource.username=postgres -spring.datasource.password=dila2001 +spring.datasource.password= spring.datasource.driver-class-name=org.postgresql.Driver # JPA/Hibernate Configuration