10 changed files with 7872 additions and 1519 deletions
-
14src/main/java/com/gcc_manpower/config/SecurityConfig.java
-
12src/main/java/com/gcc_manpower/config/WebConfig.java
-
518src/main/java/com/gcc_manpower/gccrentalmanagement/controller/RentalController.java
-
491src/main/java/com/gcc_manpower/gccrentalmanagement/service/RentalService.java
-
247src/main/java/com/gcc_manpower/gcctonermanagement/controller/TonerController.java
-
272src/main/java/com/gcc_manpower/gcctonermanagement/service/TonerService.java
-
22src/main/resources/templates/fragments/rentalheader.html
-
3080src/main/resources/templates/gccrentalmanagement/dashboard.html
-
429src/main/resources/templates/gccrentalmanagement/login.html
-
4306src/main/resources/templates/gcctonermanagement/upload.html
@ -0,0 +1,518 @@ |
|||
package com.gcc_manpower.gccrentalmanagement.controller; |
|||
|
|||
import java.io.File; |
|||
import java.io.FileOutputStream; |
|||
import java.io.InputStream; |
|||
import java.io.OutputStream; |
|||
import java.text.SimpleDateFormat; |
|||
import java.util.Date; |
|||
import java.util.HashMap; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.stereotype.Controller; |
|||
import org.springframework.ui.Model; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.PostMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RequestParam; |
|||
import org.springframework.web.bind.annotation.ResponseBody; |
|||
import org.springframework.web.multipart.MultipartFile; |
|||
|
|||
import com.gcc_manpower.gccrentalmanagement.service.RentalService; |
|||
import com.gcc_manpower.service.AppUserService; |
|||
import jakarta.servlet.http.HttpSession; |
|||
import jakarta.servlet.http.HttpServletRequest; |
|||
|
|||
import org.springframework.security.authentication.AuthenticationManager; |
|||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; |
|||
import org.springframework.security.core.Authentication; |
|||
import org.springframework.security.core.AuthenticationException; |
|||
import org.springframework.security.core.context.SecurityContextHolder; |
|||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository; |
|||
|
|||
@Controller |
|||
@RequestMapping("/gccrentalmanagement") |
|||
public class RentalController { |
|||
|
|||
@Autowired |
|||
private AppUserService appUserService; |
|||
|
|||
@Autowired |
|||
private RentalService rentalService; |
|||
|
|||
@Autowired |
|||
private AuthenticationManager authenticationManager; |
|||
|
|||
@Value("${rental.upload.path:gccrentalmanagementfiles}") |
|||
private String rentalUploadPathConfig; |
|||
|
|||
@GetMapping({ "", "/", "/dashboard" }) |
|||
public String viewDashboard(Model model, HttpSession session) { |
|||
String username = (String) session.getAttribute("rental_usrName"); |
|||
if (username == null) { |
|||
return "redirect:/gccrentalmanagement/login"; |
|||
} |
|||
|
|||
String usrRole = (String) session.getAttribute("rental_usrRole"); |
|||
boolean isAdmin = "ADMIN".equalsIgnoreCase(usrRole); |
|||
|
|||
model.addAttribute("isLoggedIn", true); |
|||
model.addAttribute("isAdmin", isAdmin); |
|||
model.addAttribute("usrName", username); |
|||
model.addAttribute("usrRole", usrRole != null ? usrRole : "USER"); |
|||
model.addAttribute("curPage", "gccrentalmanagement"); |
|||
|
|||
return "gccrentalmanagement/dashboard"; |
|||
} |
|||
|
|||
@GetMapping("/login") |
|||
public String login(HttpSession session) { |
|||
String username = (String) session.getAttribute("rental_usrName"); |
|||
if (username != null) { |
|||
return "redirect:/gccrentalmanagement/dashboard"; |
|||
} |
|||
return "gccrentalmanagement/login"; |
|||
} |
|||
|
|||
@PostMapping("/api/login") |
|||
@ResponseBody |
|||
public Map<String, Object> validateLogin( |
|||
@RequestParam("usrName") String usrName, |
|||
@RequestParam("usrPass") String usrPass, |
|||
HttpSession session) { |
|||
|
|||
Map<String, Object> response = new HashMap<>(); |
|||
|
|||
try { |
|||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(usrName, usrPass); |
|||
Authentication authentication = authenticationManager.authenticate(authenticationToken); |
|||
|
|||
SecurityContextHolder.getContext().setAuthentication(authentication); |
|||
session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, |
|||
SecurityContextHolder.getContext()); |
|||
|
|||
String role = authentication.getAuthorities().stream() |
|||
.map(auth -> auth.getAuthority().replace("ROLE_", "")) |
|||
.findFirst() |
|||
.orElse("USER"); |
|||
|
|||
session.setAttribute("rental_usrName", usrName); |
|||
session.setAttribute("rental_usrRole", role); |
|||
session.setMaxInactiveInterval(1800); // 30 minutes session timeout |
|||
response.put("result", true); |
|||
response.put("usrName", usrName); |
|||
response.put("usrRole", role); |
|||
} catch (AuthenticationException e) { |
|||
response.put("result", false); |
|||
response.put("error", e.getMessage() != null ? e.getMessage() : "Invalid username or password!"); |
|||
} |
|||
|
|||
return response; |
|||
} |
|||
|
|||
@GetMapping("/logout") |
|||
public String logoutGet(HttpSession session, HttpServletRequest request) { |
|||
SecurityContextHolder.clearContext(); |
|||
if (session != null) { |
|||
session.removeAttribute("rental_usrName"); |
|||
session.removeAttribute("rental_usrRole"); |
|||
session.invalidate(); |
|||
} |
|||
request.getSession(true); |
|||
return "redirect:/gccrentalmanagement/login"; |
|||
} |
|||
|
|||
@PostMapping("/logout") |
|||
public String logoutPost(HttpSession session, HttpServletRequest request) { |
|||
return logoutGet(session, request); |
|||
} |
|||
|
|||
// ========================================================================= |
|||
// MASTER LOOKUPS APIS |
|||
// ========================================================================= |
|||
|
|||
@GetMapping("/api/departments") |
|||
@ResponseBody |
|||
public List<Map<String, Object>> getDepartments(HttpSession session) { |
|||
return rentalService.getActiveDepartments(); |
|||
} |
|||
|
|||
@GetMapping("/api/zones") |
|||
@ResponseBody |
|||
public List<Map<String, Object>> getZones(HttpSession session) { |
|||
return rentalService.getActiveZones(); |
|||
} |
|||
|
|||
@GetMapping("/api/vendors") |
|||
@ResponseBody |
|||
public List<Map<String, Object>> getVendors(HttpSession session) { |
|||
return rentalService.getActiveVendors(); |
|||
} |
|||
|
|||
@GetMapping("/api/statuses") |
|||
@ResponseBody |
|||
public List<Map<String, Object>> getStatuses( |
|||
@RequestParam(value = "type", required = false) String type, |
|||
HttpSession session) { |
|||
return rentalService.getMasterStatuses(type); |
|||
} |
|||
|
|||
// ========================================================================= |
|||
// 1. WORK ORDER (WO) APIS |
|||
// ========================================================================= |
|||
|
|||
@GetMapping("/api/workorders") |
|||
@ResponseBody |
|||
public List<Map<String, Object>> getWorkOrders(HttpSession session) { |
|||
return rentalService.getAllWorkOrders(); |
|||
} |
|||
|
|||
@PostMapping("/api/workorders/save") |
|||
@ResponseBody |
|||
public Map<String, Object> saveWorkOrder( |
|||
@RequestParam("woFileNo") String woFileNo, |
|||
@RequestParam("fileSubject") String fileSubject, |
|||
@RequestParam("periodFromDate") String periodFromDate, |
|||
@RequestParam("periodToDate") String periodToDate, |
|||
@RequestParam("vendorName") String vendorName, |
|||
@RequestParam(value = "systemsQty", defaultValue = "0") Integer systemsQty, |
|||
@RequestParam(value = "systemsModel", defaultValue = "") String systemsModel, |
|||
@RequestParam(value = "printersQty", defaultValue = "0") Integer printersQty, |
|||
@RequestParam(value = "printersModel", defaultValue = "") String printersModel, |
|||
@RequestParam(value = "laptopsQty", defaultValue = "0") Integer laptopsQty, |
|||
@RequestParam(value = "laptopsModel", defaultValue = "") String laptopsModel, |
|||
@RequestParam(value = "woCopyFile", required = false) MultipartFile woCopyFile, |
|||
@RequestParam(value = "remarks", defaultValue = "") String remarks, |
|||
HttpSession session) { |
|||
|
|||
Map<String, Object> response = new HashMap<>(); |
|||
String username = (String) session.getAttribute("rental_usrName"); |
|||
if (username == null) { |
|||
response.put("success", false); |
|||
response.put("error", "Unauthorized access. Please log in."); |
|||
return response; |
|||
} |
|||
|
|||
try { |
|||
File uploadDir = new File(rentalUploadPathConfig).getAbsoluteFile(); |
|||
if (!uploadDir.exists()) uploadDir.mkdirs(); |
|||
|
|||
String woCopyPath = null; |
|||
if (woCopyFile != null && !woCopyFile.isEmpty()) { |
|||
woCopyPath = saveUploadedFile(woCopyFile, "wo", uploadDir); |
|||
} |
|||
|
|||
boolean saved = rentalService.saveWorkOrder( |
|||
woFileNo, fileSubject, periodFromDate, periodToDate, vendorName, |
|||
systemsQty, systemsModel, printersQty, printersModel, |
|||
laptopsQty, laptopsModel, woCopyPath, remarks, username); |
|||
|
|||
if (saved) { |
|||
response.put("success", true); |
|||
response.put("message", "Work order registered successfully."); |
|||
} else { |
|||
response.put("success", false); |
|||
response.put("error", "Failed to save work order to database."); |
|||
} |
|||
} catch (Exception e) { |
|||
response.put("success", false); |
|||
response.put("error", "Error: " + e.getMessage()); |
|||
} |
|||
return response; |
|||
} |
|||
|
|||
// ========================================================================= |
|||
// 2. DEPARTMENT USER REQUEST APIS |
|||
// ========================================================================= |
|||
|
|||
@GetMapping("/api/requests") |
|||
@ResponseBody |
|||
public List<Map<String, Object>> getRequests(HttpSession session) { |
|||
return rentalService.getAllUserRequests(); |
|||
} |
|||
|
|||
@PostMapping("/api/requests/save") |
|||
@ResponseBody |
|||
public Map<String, Object> saveUserRequest( |
|||
@RequestParam("tapalNo") String tapalNo, |
|||
@RequestParam("tapalDate") String tapalDate, |
|||
@RequestParam("deptId") Integer deptId, |
|||
@RequestParam(value = "zoneId", required = false) Integer zoneId, |
|||
@RequestParam(value = "reqSystemsQty", defaultValue = "0") Integer reqSystemsQty, |
|||
@RequestParam(value = "reqPrintersQty", defaultValue = "0") Integer reqPrintersQty, |
|||
@RequestParam(value = "reqLaptopsQty", defaultValue = "0") Integer reqLaptopsQty, |
|||
@RequestParam("requiredFromDate") String requiredFromDate, |
|||
@RequestParam("requiredToDate") String requiredToDate, |
|||
@RequestParam(value = "mailCopyFile", required = false) MultipartFile mailCopyFile, |
|||
@RequestParam(value = "reqStatusId", defaultValue = "1") Integer reqStatusId, |
|||
@RequestParam(value = "requestingOfficer", defaultValue = "") String requestingOfficer, |
|||
@RequestParam(value = "contactNo", defaultValue = "") String contactNo, |
|||
@RequestParam(value = "purpose", defaultValue = "") String purpose, |
|||
HttpSession session) { |
|||
|
|||
Map<String, Object> response = new HashMap<>(); |
|||
String username = (String) session.getAttribute("rental_usrName"); |
|||
if (username == null) { |
|||
response.put("success", false); |
|||
response.put("error", "Unauthorized access. Please log in."); |
|||
return response; |
|||
} |
|||
|
|||
try { |
|||
File uploadDir = new File(rentalUploadPathConfig).getAbsoluteFile(); |
|||
if (!uploadDir.exists()) uploadDir.mkdirs(); |
|||
|
|||
String mailCopyPath = null; |
|||
if (mailCopyFile != null && !mailCopyFile.isEmpty()) { |
|||
mailCopyPath = saveUploadedFile(mailCopyFile, "request_mail", uploadDir); |
|||
} |
|||
|
|||
boolean saved = rentalService.saveUserRequest( |
|||
tapalNo, tapalDate, deptId, zoneId, |
|||
reqSystemsQty, reqPrintersQty, reqLaptopsQty, |
|||
requiredFromDate, requiredToDate, mailCopyPath, reqStatusId, |
|||
requestingOfficer, contactNo, purpose, username); |
|||
|
|||
if (saved) { |
|||
response.put("success", true); |
|||
response.put("message", "Department request registered successfully."); |
|||
} else { |
|||
response.put("success", false); |
|||
response.put("error", "Failed to save department request."); |
|||
} |
|||
} catch (Exception e) { |
|||
response.put("success", false); |
|||
response.put("error", "Error: " + e.getMessage()); |
|||
} |
|||
return response; |
|||
} |
|||
|
|||
// ========================================================================= |
|||
// 3. INWARD DELIVERY CHALLAN (DC) APIS |
|||
// ========================================================================= |
|||
|
|||
@GetMapping("/api/inward-challans") |
|||
@ResponseBody |
|||
public List<Map<String, Object>> getInwardChallans(HttpSession session) { |
|||
return rentalService.getAllInwardChallans(); |
|||
} |
|||
|
|||
@PostMapping("/api/inward-challans/save") |
|||
@ResponseBody |
|||
public Map<String, Object> saveInwardChallan( |
|||
@RequestParam("woId") Integer woId, |
|||
@RequestParam("dcNo") String dcNo, |
|||
@RequestParam("dcDate") String dcDate, |
|||
@RequestParam(value = "vendorName", defaultValue = "") String vendorName, |
|||
@RequestParam(value = "inSystemsQty", defaultValue = "0") Integer inSystemsQty, |
|||
@RequestParam(value = "inPrintersQty", defaultValue = "0") Integer inPrintersQty, |
|||
@RequestParam(value = "inLaptopsQty", defaultValue = "0") Integer inLaptopsQty, |
|||
@RequestParam(value = "dcFile", required = false) MultipartFile dcFile, |
|||
@RequestParam(value = "vehicleNo", defaultValue = "") String vehicleNo, |
|||
@RequestParam(value = "receivedBy", defaultValue = "") String receivedBy, |
|||
@RequestParam(value = "remarks", defaultValue = "") String remarks, |
|||
HttpSession session) { |
|||
|
|||
Map<String, Object> response = new HashMap<>(); |
|||
String username = (String) session.getAttribute("rental_usrName"); |
|||
if (username == null) { |
|||
response.put("success", false); |
|||
response.put("error", "Unauthorized access. Please log in."); |
|||
return response; |
|||
} |
|||
|
|||
try { |
|||
File uploadDir = new File(rentalUploadPathConfig).getAbsoluteFile(); |
|||
if (!uploadDir.exists()) uploadDir.mkdirs(); |
|||
|
|||
String dcFilePath = null; |
|||
if (dcFile != null && !dcFile.isEmpty()) { |
|||
dcFilePath = saveUploadedFile(dcFile, "inward_dc", uploadDir); |
|||
} |
|||
|
|||
boolean saved = rentalService.saveInwardChallan( |
|||
woId, dcNo, dcDate, vendorName, |
|||
inSystemsQty, inPrintersQty, inLaptopsQty, |
|||
dcFilePath, vehicleNo, receivedBy, remarks, username); |
|||
|
|||
if (saved) { |
|||
response.put("success", true); |
|||
response.put("message", "Inward Delivery Challan registered successfully."); |
|||
} else { |
|||
response.put("success", false); |
|||
response.put("error", "Failed to save inward Delivery Challan."); |
|||
} |
|||
} catch (Exception e) { |
|||
response.put("success", false); |
|||
response.put("error", "Error: " + e.getMessage()); |
|||
} |
|||
return response; |
|||
} |
|||
|
|||
// ========================================================================= |
|||
// 4. ISSUED DETAILS APIS |
|||
// ========================================================================= |
|||
|
|||
@GetMapping("/api/issued-assets") |
|||
@ResponseBody |
|||
public List<Map<String, Object>> getIssuedAssets(HttpSession session) { |
|||
return rentalService.getAllIssuedDetails(); |
|||
} |
|||
|
|||
@PostMapping("/api/issued-assets/save") |
|||
@ResponseBody |
|||
public Map<String, Object> saveIssuedDetails( |
|||
@RequestParam("requestId") Integer requestId, |
|||
@RequestParam(value = "inwardDcId", required = false) Integer inwardDcId, |
|||
@RequestParam(value = "woId", required = false) Integer woId, |
|||
@RequestParam("issuedDate") String issuedDate, |
|||
@RequestParam(value = "issuedSystemsQty", defaultValue = "0") Integer issuedSystemsQty, |
|||
@RequestParam(value = "issuedPrintersQty", defaultValue = "0") Integer issuedPrintersQty, |
|||
@RequestParam(value = "issuedLaptopsQty", defaultValue = "0") Integer issuedLaptopsQty, |
|||
@RequestParam(value = "assetSerialDetails", defaultValue = "") String assetSerialDetails, |
|||
@RequestParam("issuedFromDate") String issuedFromDate, |
|||
@RequestParam("issuedToDate") String issuedToDate, |
|||
@RequestParam(value = "stockCopyFile", required = false) MultipartFile stockCopyFile, |
|||
@RequestParam(value = "custodianOfficer", defaultValue = "") String custodianOfficer, |
|||
@RequestParam(value = "contactNo", defaultValue = "") String contactNo, |
|||
@RequestParam(value = "issuedBy", defaultValue = "") String issuedBy, |
|||
HttpSession session) { |
|||
|
|||
Map<String, Object> response = new HashMap<>(); |
|||
String username = (String) session.getAttribute("rental_usrName"); |
|||
if (username == null) { |
|||
response.put("success", false); |
|||
response.put("error", "Unauthorized access. Please log in."); |
|||
return response; |
|||
} |
|||
|
|||
try { |
|||
File uploadDir = new File(rentalUploadPathConfig).getAbsoluteFile(); |
|||
if (!uploadDir.exists()) uploadDir.mkdirs(); |
|||
|
|||
String stockCopyPath = null; |
|||
if (stockCopyFile != null && !stockCopyFile.isEmpty()) { |
|||
stockCopyPath = saveUploadedFile(stockCopyFile, "issue_stock", uploadDir); |
|||
} |
|||
|
|||
boolean saved = rentalService.saveIssuedDetails( |
|||
requestId, inwardDcId, woId, issuedDate, |
|||
issuedSystemsQty, issuedPrintersQty, issuedLaptopsQty, |
|||
assetSerialDetails, issuedFromDate, issuedToDate, stockCopyPath, |
|||
custodianOfficer, contactNo, issuedBy, username); |
|||
|
|||
if (saved) { |
|||
response.put("success", true); |
|||
response.put("message", "Asset issued successfully."); |
|||
} else { |
|||
response.put("success", false); |
|||
response.put("error", "Failed to register issued details."); |
|||
} |
|||
} catch (Exception e) { |
|||
response.put("success", false); |
|||
response.put("error", "Error: " + e.getMessage()); |
|||
} |
|||
return response; |
|||
} |
|||
|
|||
// ========================================================================= |
|||
// 5. RETURN DETAILS APIS |
|||
// ========================================================================= |
|||
|
|||
@GetMapping("/api/returns") |
|||
@ResponseBody |
|||
public List<Map<String, Object>> getReturns(HttpSession session) { |
|||
return rentalService.getAllReturnDetails(); |
|||
} |
|||
|
|||
@PostMapping("/api/returns/save") |
|||
@ResponseBody |
|||
public Map<String, Object> saveReturnDetails( |
|||
@RequestParam("issueId") Integer issueId, |
|||
@RequestParam("requestId") Integer requestId, |
|||
@RequestParam("returnDate") String returnDate, |
|||
@RequestParam(value = "retSystemsQty", defaultValue = "0") Integer retSystemsQty, |
|||
@RequestParam(value = "retPrintersQty", defaultValue = "0") Integer retPrintersQty, |
|||
@RequestParam(value = "retLaptopsQty", defaultValue = "0") Integer retLaptopsQty, |
|||
@RequestParam(value = "stockCopyFile", required = false) MultipartFile stockCopyFile, |
|||
@RequestParam(value = "postReturnStatusId", defaultValue = "6") Integer postReturnStatusId, |
|||
@RequestParam(value = "conditionGrade", defaultValue = "Good") String conditionGrade, |
|||
@RequestParam(value = "penaltyCharges", defaultValue = "0.0") Double penaltyCharges, |
|||
@RequestParam(value = "receivedBy", defaultValue = "") String receivedBy, |
|||
@RequestParam(value = "remarks", defaultValue = "") String remarks, |
|||
HttpSession session) { |
|||
|
|||
Map<String, Object> response = new HashMap<>(); |
|||
String username = (String) session.getAttribute("rental_usrName"); |
|||
if (username == null) { |
|||
response.put("success", false); |
|||
response.put("error", "Unauthorized access. Please log in."); |
|||
return response; |
|||
} |
|||
|
|||
try { |
|||
File uploadDir = new File(rentalUploadPathConfig).getAbsoluteFile(); |
|||
if (!uploadDir.exists()) uploadDir.mkdirs(); |
|||
|
|||
String stockCopyPath = null; |
|||
if (stockCopyFile != null && !stockCopyFile.isEmpty()) { |
|||
stockCopyPath = saveUploadedFile(stockCopyFile, "return_stock", uploadDir); |
|||
} |
|||
|
|||
boolean saved = rentalService.saveReturnDetails( |
|||
issueId, requestId, returnDate, |
|||
retSystemsQty, retPrintersQty, retLaptopsQty, |
|||
stockCopyPath, postReturnStatusId, conditionGrade, |
|||
penaltyCharges, receivedBy, remarks, username); |
|||
|
|||
if (saved) { |
|||
response.put("success", true); |
|||
response.put("message", "Asset return intake processed successfully."); |
|||
} else { |
|||
response.put("success", false); |
|||
response.put("error", "Failed to register return details."); |
|||
} |
|||
} catch (Exception e) { |
|||
response.put("success", false); |
|||
response.put("error", "Error: " + e.getMessage()); |
|||
} |
|||
return response; |
|||
} |
|||
|
|||
// ========================================================================= |
|||
// 6. REMINDERS & DUE ALERTS API |
|||
// ========================================================================= |
|||
|
|||
@GetMapping("/api/reminders") |
|||
@ResponseBody |
|||
public List<Map<String, Object>> getReminders(HttpSession session) { |
|||
return rentalService.getOverdueAndDueSoonReminders(); |
|||
} |
|||
|
|||
// ========================================================================= |
|||
// FILE UPLOAD HELPER METHODS |
|||
// ========================================================================= |
|||
|
|||
private String saveUploadedFile(MultipartFile file, String prefix, File uploadDir) throws Exception { |
|||
String originalFilename = file.getOriginalFilename(); |
|||
String extension = ""; |
|||
if (originalFilename != null && originalFilename.contains(".")) { |
|||
extension = originalFilename.substring(originalFilename.lastIndexOf(".")); |
|||
} |
|||
String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss_SSS").format(new Date()); |
|||
String newFilename = prefix + "_" + timestamp + extension; |
|||
|
|||
File targetFile = new File(uploadDir, newFilename); |
|||
try (InputStream in = file.getInputStream(); OutputStream out = new FileOutputStream(targetFile)) { |
|||
byte[] buffer = new byte[8192]; |
|||
int bytesRead; |
|||
while ((bytesRead = in.read(buffer)) != -1) { |
|||
out.write(buffer, 0, bytesRead); |
|||
} |
|||
} |
|||
return newFilename; |
|||
} |
|||
} |
|||
@ -0,0 +1,491 @@ |
|||
package com.gcc_manpower.gccrentalmanagement.service; |
|||
|
|||
import java.sql.PreparedStatement; |
|||
import java.sql.Statement; |
|||
import java.time.LocalDate; |
|||
import java.time.temporal.ChronoUnit; |
|||
import java.util.ArrayList; |
|||
import java.util.HashMap; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
import javax.sql.DataSource; |
|||
|
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.beans.factory.annotation.Qualifier; |
|||
import org.springframework.jdbc.core.JdbcTemplate; |
|||
import org.springframework.jdbc.support.GeneratedKeyHolder; |
|||
import org.springframework.jdbc.support.KeyHolder; |
|||
import org.springframework.stereotype.Service; |
|||
import org.springframework.transaction.annotation.Transactional; |
|||
|
|||
@Service |
|||
public class RentalService { |
|||
|
|||
private JdbcTemplate jdbcTemplate; |
|||
|
|||
@Autowired |
|||
public void setDataSource(@Qualifier("mysqlItcellManagementDataSource") DataSource dataSource) { |
|||
this.jdbcTemplate = new JdbcTemplate(dataSource); |
|||
} |
|||
|
|||
public JdbcTemplate getJdbcTemplate() { |
|||
return this.jdbcTemplate; |
|||
} |
|||
|
|||
// ========================================================================= |
|||
// 1. MASTER LOOKUPS (Departments, Zones, Vendors, Master Statuses) |
|||
// ========================================================================= |
|||
|
|||
public List<Map<String, Object>> getActiveDepartments() { |
|||
String sql = "SELECT id, dept_name FROM toner_department_list WHERE (is_active IS NULL OR is_active = 1) AND (is_delete IS NULL OR is_delete = 0) ORDER BY dept_name ASC"; |
|||
try { |
|||
return jdbcTemplate.queryForList(sql); |
|||
} catch (Exception e) { |
|||
return new ArrayList<>(); |
|||
} |
|||
} |
|||
|
|||
public List<Map<String, Object>> getActiveZones() { |
|||
String sql = "SELECT id, zone_name FROM toner_zone_list WHERE (is_active IS NULL OR is_active = 1) AND (is_delete IS NULL OR is_delete = 0) ORDER BY id ASC"; |
|||
try { |
|||
return jdbcTemplate.queryForList(sql); |
|||
} catch (Exception e) { |
|||
return new ArrayList<>(); |
|||
} |
|||
} |
|||
|
|||
public List<Map<String, Object>> getActiveVendors() { |
|||
String sql = "SELECT id, vendor_name FROM payment_vendors_list WHERE (is_active IS NULL OR is_active = 1) AND (is_delete IS NULL OR is_delete = 0) ORDER BY vendor_name ASC"; |
|||
try { |
|||
return jdbcTemplate.queryForList(sql); |
|||
} catch (Exception e) { |
|||
return new ArrayList<>(); |
|||
} |
|||
} |
|||
|
|||
public List<Map<String, Object>> getMasterStatuses(String statusType) { |
|||
String sql; |
|||
try { |
|||
if (statusType != null && !statusType.trim().isEmpty() && !"ALL".equalsIgnoreCase(statusType)) { |
|||
sql = "SELECT id, status_name, status_type, badge_color FROM rental_master_status_list " + |
|||
"WHERE (is_active IS NULL OR is_active = 1) AND (is_delete IS NULL OR is_delete = 0) " + |
|||
"AND status_type = ? ORDER BY id ASC"; |
|||
return jdbcTemplate.queryForList(sql, statusType.toUpperCase().trim()); |
|||
} else { |
|||
sql = "SELECT id, status_name, status_type, badge_color FROM rental_master_status_list " + |
|||
"WHERE (is_active IS NULL OR is_active = 1) AND (is_delete IS NULL OR is_delete = 0) ORDER BY id ASC"; |
|||
return jdbcTemplate.queryForList(sql); |
|||
} |
|||
} catch (Exception e) { |
|||
return getDefaultStatusFallback(statusType); |
|||
} |
|||
} |
|||
|
|||
private List<Map<String, Object>> getDefaultStatusFallback(String type) { |
|||
List<Map<String, Object>> list = new ArrayList<>(); |
|||
if ("REQUEST".equalsIgnoreCase(type) || type == null) { |
|||
list.add(Map.of("id", 1, "status_name", "Pending Sanction", "status_type", "REQUEST", "badge_color", |
|||
"warning")); |
|||
list.add(Map.of("id", 2, "status_name", "Sanctioned & Approved", "status_type", "REQUEST", "badge_color", |
|||
"info")); |
|||
list.add(Map.of("id", 3, "status_name", "Issued to Dept", "status_type", "REQUEST", "badge_color", |
|||
"primary")); |
|||
list.add(Map.of("id", 4, "status_name", "Completed & Returned", "status_type", "REQUEST", "badge_color", |
|||
"success")); |
|||
list.add(Map.of("id", 5, "status_name", "Rejected", "status_type", "REQUEST", "badge_color", "danger")); |
|||
} |
|||
if ("RETURN".equalsIgnoreCase(type) || type == null) { |
|||
list.add(Map.of("id", 6, "status_name", "Completed", "status_type", "RETURN", "badge_color", "success")); |
|||
list.add(Map.of("id", 7, "status_name", "Partially Returned", "status_type", "RETURN", "badge_color", |
|||
"warning")); |
|||
list.add( |
|||
Map.of("id", 8, "status_name", "Pending Return", "status_type", "RETURN", "badge_color", "danger")); |
|||
} |
|||
return list; |
|||
} |
|||
|
|||
// ========================================================================= |
|||
// 2. WORK ORDER (WO) FILE CREATION & REGISTRY |
|||
// ========================================================================= |
|||
|
|||
@Transactional |
|||
public boolean saveWorkOrder(String woFileNo, String fileSubject, String fromDate, String toDate, |
|||
String vendorName, Integer systemsQty, String systemsModel, |
|||
Integer printersQty, String printersModel, Integer laptopsQty, |
|||
String laptopsModel, String woCopyPath, String remarks, String updatedBy) { |
|||
String sql = "INSERT INTO rental_workorder_register " + |
|||
"(wo_file_no, file_subject, period_from_date, period_to_date, vendor_name, " + |
|||
"systems_qty, systems_model_name, printers_qty, printers_model_name, " + |
|||
"laptops_qty, laptops_model_name, wo_copy_file, status, remarks, created_by, is_active, is_delete) " + |
|||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'Active', ?, ?, 1, 0)"; |
|||
try { |
|||
int rows = jdbcTemplate.update(sql, |
|||
woFileNo != null ? woFileNo.trim() : null, |
|||
fileSubject != null ? fileSubject.trim() : null, |
|||
fromDate, toDate, |
|||
vendorName != null ? vendorName.trim() : null, |
|||
systemsQty != null ? systemsQty : 0, |
|||
systemsModel != null ? systemsModel.trim() : "", |
|||
printersQty != null ? printersQty : 0, |
|||
printersModel != null ? printersModel.trim() : "", |
|||
laptopsQty != null ? laptopsQty : 0, |
|||
laptopsModel != null ? laptopsModel.trim() : "", |
|||
woCopyPath, remarks, updatedBy); |
|||
return rows > 0; |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
public List<Map<String, Object>> getAllWorkOrders() { |
|||
String sql = "SELECT id, wo_file_no, file_subject, period_from_date, period_to_date, vendor_name, " + |
|||
"systems_qty, systems_model_name, printers_qty, printers_model_name, " + |
|||
"laptops_qty, laptops_model_name, (systems_qty + printers_qty + laptops_qty) AS total_units, " + |
|||
"wo_copy_file, status, remarks, created_by, created_at " + |
|||
"FROM rental_workorder_register " + |
|||
"WHERE (is_active IS NULL OR is_active = 1) AND (is_delete IS NULL OR is_delete = 0) " + |
|||
"ORDER BY id DESC"; |
|||
try { |
|||
return jdbcTemplate.queryForList(sql); |
|||
} catch (Exception e) { |
|||
return new ArrayList<>(); |
|||
} |
|||
} |
|||
|
|||
public Map<String, Object> getWorkOrderById(int id) { |
|||
String sql = "SELECT * FROM rental_workorder_register WHERE id = ?"; |
|||
try { |
|||
return jdbcTemplate.queryForMap(sql, id); |
|||
} catch (Exception e) { |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
// ========================================================================= |
|||
// 3. DEPARTMENT USER REQUEST CREATION (Tapal, Dept, Zone, Qty, Dates) |
|||
// ========================================================================= |
|||
|
|||
@Transactional |
|||
public boolean saveUserRequest(String tapalNo, String tapalDate, Integer deptId, Integer zoneId, |
|||
Integer reqSystemsQty, Integer reqPrintersQty, Integer reqLaptopsQty, |
|||
String fromDate, String toDate, String mailCopyPath, Integer statusId, |
|||
String requestingOfficer, String contactNo, String purpose, String updatedBy) { |
|||
|
|||
int calculatedDays = calculateDaysBetween(fromDate, toDate); |
|||
int finalStatusId = (statusId != null && statusId > 0) ? statusId : 1; // Default to 'Pending Sanction' |
|||
|
|||
String sql = "INSERT INTO rental_user_request " + |
|||
"(tapal_no, tapal_date, department_id, zone_id, " + |
|||
"req_systems_qty, req_printers_qty, req_laptops_qty, " + |
|||
"required_from_date, required_to_date, calculated_days, " + |
|||
"mail_copy_file, req_status_id, requesting_officer, contact_no, purpose, " + |
|||
"created_by, is_active, is_delete) " + |
|||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, 0)"; |
|||
try { |
|||
int rows = jdbcTemplate.update(sql, |
|||
tapalNo != null ? tapalNo.trim() : null, |
|||
tapalDate, |
|||
deptId, zoneId, |
|||
reqSystemsQty != null ? reqSystemsQty : 0, |
|||
reqPrintersQty != null ? reqPrintersQty : 0, |
|||
reqLaptopsQty != null ? reqLaptopsQty : 0, |
|||
fromDate, toDate, calculatedDays, |
|||
mailCopyPath, finalStatusId, |
|||
requestingOfficer != null ? requestingOfficer.trim() : null, |
|||
contactNo != null ? contactNo.trim() : null, |
|||
purpose, updatedBy); |
|||
return rows > 0; |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
public List<Map<String, Object>> getAllUserRequests() { |
|||
String sql = "SELECT r.id, r.tapal_no, r.tapal_date, r.department_id, d.dept_name, " + |
|||
"r.zone_id, z.zone_name, r.req_systems_qty, r.req_printers_qty, r.req_laptops_qty, " + |
|||
"(r.req_systems_qty + r.req_printers_qty + r.req_laptops_qty) AS total_req_qty, " + |
|||
"r.required_from_date, r.required_to_date, r.calculated_days, r.mail_copy_file, " + |
|||
"r.req_status_id, COALESCE(s.status_name, 'Pending') AS status_name, " + |
|||
"COALESCE(s.badge_color, 'warning') AS badge_color, " + |
|||
"r.requesting_officer, r.contact_no, r.purpose, r.created_by, r.created_at " + |
|||
"FROM rental_user_request r " + |
|||
"LEFT JOIN toner_department_list d ON r.department_id = d.id " + |
|||
"LEFT JOIN toner_zone_list z ON r.zone_id = z.id " + |
|||
"LEFT JOIN rental_master_status_list s ON r.req_status_id = s.id " + |
|||
"WHERE (r.is_active IS NULL OR r.is_active = 1) AND (r.is_delete IS NULL OR r.is_delete = 0) " + |
|||
"ORDER BY r.id DESC"; |
|||
try { |
|||
return jdbcTemplate.queryForList(sql); |
|||
} catch (Exception e) { |
|||
return new ArrayList<>(); |
|||
} |
|||
} |
|||
|
|||
@Transactional |
|||
public boolean updateUserRequestStatus(int requestId, int statusId, String updatedBy) { |
|||
String sql = "UPDATE rental_user_request SET req_status_id = ? WHERE id = ?"; |
|||
try { |
|||
return jdbcTemplate.update(sql, statusId, requestId) > 0; |
|||
} catch (Exception e) { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
// ========================================================================= |
|||
// 4. DELIVERY CHALLAN (DC) - INWARD STOCK AGAINST REGISTERED WORK ORDER |
|||
// ========================================================================= |
|||
|
|||
@Transactional |
|||
public boolean saveInwardChallan(Integer woId, String dcNo, String dcDate, String vendorName, |
|||
Integer inSystemsQty, Integer inPrintersQty, Integer inLaptopsQty, |
|||
String dcFilePath, String vehicleNo, String receivedBy, |
|||
String remarks, String updatedBy) { |
|||
String sql = "INSERT INTO rental_inward_delivery_challan " + |
|||
"(wo_id, dc_no, dc_date, vendor_name, " + |
|||
"inward_systems_qty, inward_printers_qty, inward_laptops_qty, " + |
|||
"dc_file_path, vehicle_no, received_by, remarks, created_by, is_active, is_delete) " + |
|||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, 0)"; |
|||
try { |
|||
int rows = jdbcTemplate.update(sql, |
|||
woId, |
|||
dcNo != null ? dcNo.trim() : null, |
|||
dcDate, |
|||
vendorName != null ? vendorName.trim() : null, |
|||
inSystemsQty != null ? inSystemsQty : 0, |
|||
inPrintersQty != null ? inPrintersQty : 0, |
|||
inLaptopsQty != null ? inLaptopsQty : 0, |
|||
dcFilePath, |
|||
vehicleNo != null ? vehicleNo.trim() : null, |
|||
receivedBy != null ? receivedBy.trim() : null, |
|||
remarks, updatedBy); |
|||
return rows > 0; |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
public List<Map<String, Object>> getAllInwardChallans() { |
|||
String sql = "SELECT c.id, c.wo_id, w.wo_file_no, w.file_subject, c.dc_no, c.dc_date, " + |
|||
"COALESCE(c.vendor_name, w.vendor_name) AS vendor_name, " + |
|||
"c.inward_systems_qty, c.inward_printers_qty, c.inward_laptops_qty, " + |
|||
"(c.inward_systems_qty + c.inward_printers_qty + c.inward_laptops_qty) AS total_inward_qty, " + |
|||
"c.dc_file_path, c.vehicle_no, c.received_by, c.remarks, c.created_by, c.created_at " + |
|||
"FROM rental_inward_delivery_challan c " + |
|||
"LEFT JOIN rental_workorder_register w ON c.wo_id = w.id " + |
|||
"WHERE (c.is_active IS NULL OR c.is_active = 1) AND (c.is_delete IS NULL OR c.is_delete = 0) " + |
|||
"ORDER BY c.id DESC"; |
|||
try { |
|||
return jdbcTemplate.queryForList(sql); |
|||
} catch (Exception e) { |
|||
return new ArrayList<>(); |
|||
} |
|||
} |
|||
|
|||
// ========================================================================= |
|||
// 5. ISSUED DETAILS (From Inward Stock & User Request) |
|||
// ========================================================================= |
|||
|
|||
@Transactional |
|||
public boolean saveIssuedDetails(Integer requestId, Integer inwardDcId, Integer woId, |
|||
String issuedDate, Integer issuedSystemsQty, Integer issuedPrintersQty, |
|||
Integer issuedLaptopsQty, String assetSerialDetails, |
|||
String issuedFromDate, String issuedToDate, String stockCopyPath, |
|||
String custodianOfficer, String contactNo, String issuedBy, String updatedBy) { |
|||
|
|||
int periodDays = calculateDaysBetween(issuedFromDate, issuedToDate); |
|||
|
|||
String sql = "INSERT INTO rental_issued_details " + |
|||
"(request_id, inward_dc_id, wo_id, issued_date, " + |
|||
"issued_systems_qty, issued_printers_qty, issued_laptops_qty, " + |
|||
"asset_serial_details, issued_from_date, issued_to_date, issued_period_days, " + |
|||
"stock_copy_path, custodian_officer, contact_no, issued_by, status, " + |
|||
"created_by, is_active, is_delete) " + |
|||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'Issued', ?, 1, 0)"; |
|||
try { |
|||
int rows = jdbcTemplate.update(sql, |
|||
requestId, inwardDcId, woId, issuedDate, |
|||
issuedSystemsQty != null ? issuedSystemsQty : 0, |
|||
issuedPrintersQty != null ? issuedPrintersQty : 0, |
|||
issuedLaptopsQty != null ? issuedLaptopsQty : 0, |
|||
assetSerialDetails, issuedFromDate, issuedToDate, periodDays, |
|||
stockCopyPath, |
|||
custodianOfficer != null ? custodianOfficer.trim() : null, |
|||
contactNo != null ? contactNo.trim() : null, |
|||
issuedBy != null ? issuedBy.trim() : null, |
|||
updatedBy); |
|||
|
|||
if (rows > 0 && requestId != null) { |
|||
// Automatically update request status to 'Issued' (status_id = 3) |
|||
jdbcTemplate.update("UPDATE rental_user_request SET req_status_id = 3 WHERE id = ?", requestId); |
|||
} |
|||
return rows > 0; |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
public List<Map<String, Object>> getAllIssuedDetails() { |
|||
String sql = "SELECT i.id, i.request_id, r.tapal_no, d.dept_name, z.zone_name, " + |
|||
"i.inward_dc_id, dc.dc_no, i.wo_id, w.wo_file_no, i.issued_date, " + |
|||
"i.issued_systems_qty, i.issued_printers_qty, i.issued_laptops_qty, " + |
|||
"(i.issued_systems_qty + i.issued_printers_qty + i.issued_laptops_qty) AS total_issued_qty, " + |
|||
"i.asset_serial_details, i.issued_from_date, i.issued_to_date, i.issued_period_days, " + |
|||
"i.stock_copy_path, i.custodian_officer, i.contact_no, i.issued_by, i.status, " + |
|||
"i.created_by, i.created_at, " + |
|||
"COALESCE(ret.total_returned_qty, 0) AS total_returned_qty " + |
|||
"FROM rental_issued_details i " + |
|||
"LEFT JOIN rental_user_request r ON i.request_id = r.id " + |
|||
"LEFT JOIN toner_department_list d ON r.department_id = d.id " + |
|||
"LEFT JOIN toner_zone_list z ON r.zone_id = z.id " + |
|||
"LEFT JOIN rental_inward_delivery_challan dc ON i.inward_dc_id = dc.id " + |
|||
"LEFT JOIN rental_workorder_register w ON i.wo_id = w.id " + |
|||
"LEFT JOIN (SELECT issue_id, SUM(returned_systems_qty + returned_printers_qty + returned_laptops_qty) AS total_returned_qty " |
|||
+ |
|||
" FROM rental_return_details WHERE is_delete = 0 GROUP BY issue_id) ret ON i.id = ret.issue_id " |
|||
+ |
|||
"WHERE (i.is_active IS NULL OR i.is_active = 1) AND (i.is_delete IS NULL OR i.is_delete = 0) " + |
|||
"ORDER BY i.id DESC"; |
|||
try { |
|||
return jdbcTemplate.queryForList(sql); |
|||
} catch (Exception e) { |
|||
return new ArrayList<>(); |
|||
} |
|||
} |
|||
|
|||
// ========================================================================= |
|||
// 6. RETURN DETAILS (Return Date, Returned Qty, Stock Copy, Status) |
|||
// ========================================================================= |
|||
|
|||
@Transactional |
|||
public boolean saveReturnDetails(Integer issueId, Integer requestId, String returnDate, |
|||
Integer retSystemsQty, Integer retPrintersQty, Integer retLaptopsQty, |
|||
String stockCopyPath, Integer postReturnStatusId, String conditionGrade, |
|||
Double penaltyCharges, String receivedBy, String remarks, String updatedBy) { |
|||
|
|||
int finalStatusId = (postReturnStatusId != null && postReturnStatusId > 0) ? postReturnStatusId : 6; // Default |
|||
// to |
|||
// 'Completed' |
|||
|
|||
String sql = "INSERT INTO rental_return_details " + |
|||
"(issue_id, request_id, return_date, " + |
|||
"returned_systems_qty, returned_printers_qty, returned_laptops_qty, " + |
|||
"stock_copy_path, post_return_status_id, condition_grade, penalty_charges, " + |
|||
"received_by, remarks, created_by, is_active, is_delete) " + |
|||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, 0)"; |
|||
try { |
|||
int rows = jdbcTemplate.update(sql, |
|||
issueId, requestId, returnDate, |
|||
retSystemsQty != null ? retSystemsQty : 0, |
|||
retPrintersQty != null ? retPrintersQty : 0, |
|||
retLaptopsQty != null ? retLaptopsQty : 0, |
|||
stockCopyPath, finalStatusId, |
|||
conditionGrade != null ? conditionGrade.trim() : "Good", |
|||
penaltyCharges != null ? penaltyCharges : 0.0, |
|||
receivedBy != null ? receivedBy.trim() : null, |
|||
remarks, updatedBy); |
|||
|
|||
if (rows > 0) { |
|||
// Update issued details status |
|||
String postStatusText = (finalStatusId == 6) ? "Returned - Completed" : "Partially Returned"; |
|||
if (issueId != null) { |
|||
jdbcTemplate.update("UPDATE rental_issued_details SET status = ? WHERE id = ?", postStatusText, |
|||
issueId); |
|||
} |
|||
if (requestId != null && finalStatusId == 6) { |
|||
jdbcTemplate.update("UPDATE rental_user_request SET req_status_id = 4 WHERE id = ?", requestId); // 4 |
|||
// = |
|||
// Completed |
|||
} |
|||
} |
|||
return rows > 0; |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
public List<Map<String, Object>> getAllReturnDetails() { |
|||
String sql = "SELECT rt.id, rt.issue_id, rt.request_id, r.tapal_no, d.dept_name, z.zone_name, " + |
|||
"iss.custodian_officer, iss.issued_to_date, rt.return_date, " + |
|||
"rt.returned_systems_qty, rt.returned_printers_qty, rt.returned_laptops_qty, " + |
|||
"(rt.returned_systems_qty + rt.returned_printers_qty + rt.returned_laptops_qty) AS total_returned_qty, " |
|||
+ |
|||
"rt.stock_copy_path, rt.post_return_status_id, " + |
|||
"COALESCE(s.status_name, 'Completed') AS post_return_status_name, " + |
|||
"COALESCE(s.badge_color, 'success') AS badge_color, " + |
|||
"rt.condition_grade, rt.penalty_charges, rt.received_by, rt.remarks, " + |
|||
"rt.created_by, rt.created_at " + |
|||
"FROM rental_return_details rt " + |
|||
"LEFT JOIN rental_issued_details iss ON rt.issue_id = iss.id " + |
|||
"LEFT JOIN rental_user_request r ON rt.request_id = r.id " + |
|||
"LEFT JOIN toner_department_list d ON r.department_id = d.id " + |
|||
"LEFT JOIN toner_zone_list z ON r.zone_id = z.id " + |
|||
"LEFT JOIN rental_master_status_list s ON rt.post_return_status_id = s.id " + |
|||
"WHERE (rt.is_active IS NULL OR rt.is_active = 1) AND (rt.is_delete IS NULL OR rt.is_delete = 0) " + |
|||
"ORDER BY rt.id DESC"; |
|||
try { |
|||
return jdbcTemplate.queryForList(sql); |
|||
} catch (Exception e) { |
|||
return new ArrayList<>(); |
|||
} |
|||
} |
|||
|
|||
// ========================================================================= |
|||
// 7. REAL-TIME DATE MATH & REMINDERS CALCULATION |
|||
// ========================================================================= |
|||
|
|||
public List<Map<String, Object>> getOverdueAndDueSoonReminders() { |
|||
List<Map<String, Object>> issuedList = getAllIssuedDetails(); |
|||
List<Map<String, Object>> result = new ArrayList<>(); |
|||
|
|||
LocalDate today = LocalDate.now(); |
|||
|
|||
for (Map<String, Object> item : issuedList) { |
|||
Object dueDateObj = item.get("issued_to_date"); |
|||
if (dueDateObj == null) |
|||
continue; |
|||
|
|||
try { |
|||
LocalDate dueDate = LocalDate.parse(dueDateObj.toString()); |
|||
long daysDiff = ChronoUnit.DAYS.between(today, dueDate); |
|||
|
|||
Map<String, Object> alert = new HashMap<>(item); |
|||
alert.put("daysDiff", daysDiff); |
|||
|
|||
if (daysDiff < 0) { |
|||
alert.put("calculated_status", "OVERDUE"); |
|||
alert.put("overdue_days", Math.abs(daysDiff)); |
|||
alert.put("badge_class", "status-overdue"); |
|||
alert.put("status_label", "OVERDUE by " + Math.abs(daysDiff) + " Days"); |
|||
result.add(alert); |
|||
} else if (daysDiff <= 7) { |
|||
alert.put("calculated_status", "DUE_SOON"); |
|||
alert.put("due_days", daysDiff); |
|||
alert.put("badge_class", "status-due-soon"); |
|||
alert.put("status_label", "Due in " + daysDiff + " Days"); |
|||
result.add(alert); |
|||
} |
|||
} catch (Exception ignored) { |
|||
} |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
private int calculateDaysBetween(String fromDateStr, String toDateStr) { |
|||
if (fromDateStr == null || toDateStr == null) |
|||
return 0; |
|||
try { |
|||
LocalDate from = LocalDate.parse(fromDateStr); |
|||
LocalDate to = LocalDate.parse(toDateStr); |
|||
long days = ChronoUnit.DAYS.between(from, to) + 1; |
|||
return (int) Math.max(days, 0); |
|||
} catch (Exception e) { |
|||
return 0; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
<th:block th:fragment="rentalheader"> |
|||
<!-- Awesome Font --> |
|||
<link rel="stylesheet" th:href="@{/assets/font-awesome-6.5.2/css/all.min.css}" type="text/css"> |
|||
<!-- Bootstrap CSS --> |
|||
<link rel="stylesheet" th:href="@{/assets/bootstrap-5.3.2/css/bootstrap.min.css}" type="text/css"> |
|||
<!-- CSS for Header --> |
|||
<link rel="stylesheet" th:href="@{/assets/css/header-styles.css}" type="text/css"> |
|||
<div class="header"> |
|||
<div class="logo-left"> |
|||
<img th:src="@{/assets/header-images/gcc1.png}" alt="Greater Chennai Corporation Logo"> |
|||
<div class="logo-text"> |
|||
<h2>GREATER</h2> |
|||
<h2>CHENNAI</h2> |
|||
<h2>CORPORATION</h2> |
|||
<p>பெருநகர சென்னை மாநகராட்சி</p> |
|||
</div> |
|||
</div> |
|||
<div class="title"> |
|||
<h2>GCC IT Cell Rental Asset & Material Management System</h2> |
|||
</div> |
|||
</div> |
|||
</th:block> |
|||
3080
src/main/resources/templates/gccrentalmanagement/dashboard.html
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,429 @@ |
|||
<!DOCTYPE html> |
|||
<html xmlns:th="http://www.thymeleaf.org" lang="en"> |
|||
|
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<title>GCC IT Cell Rental Asset Management - Login</title> |
|||
|
|||
<!-- CSRF Tokens --> |
|||
<meta th:if="${_csrf != null}" name="_csrf" th:content="${_csrf.token}" /> |
|||
<meta th:if="${_csrf != null}" name="_csrf_header" th:content="${_csrf.headerName}" /> |
|||
|
|||
<!-- Google Fonts --> |
|||
<link rel="preconnect" href="https://fonts.googleapis.com"> |
|||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> |
|||
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700;800&family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet"> |
|||
|
|||
<!-- Bootstrap CSS --> |
|||
<link rel="stylesheet" th:href="@{/assets/bootstrap-5.3.2/css/bootstrap.min.css}" type="text/css"> |
|||
<!-- Awesome Font --> |
|||
<link th:href="@{/assets/font-awesome-6.5.2/css/all.min.css}" rel="stylesheet" type="text/css"> |
|||
|
|||
<style> |
|||
:root { |
|||
--primary-brand: #0d4b68; |
|||
--primary-dark: #072e41; |
|||
--accent-cyan: #06b6d4; |
|||
--accent-amber: #f59e0b; |
|||
--gradient-bg: linear-gradient(135deg, #072e41 0%, #0d4b68 50%, #155e75 100%); |
|||
--card-bg: rgba(255, 255, 255, 0.96); |
|||
} |
|||
|
|||
* { |
|||
margin: 0; |
|||
padding: 0; |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
body { |
|||
font-family: 'Poppins', sans-serif; |
|||
background: var(--gradient-bg); |
|||
min-height: 100vh; |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
align-items: center; |
|||
padding: 20px; |
|||
position: relative; |
|||
overflow-x: hidden; |
|||
} |
|||
|
|||
/* Decorative ambient glow circles */ |
|||
.ambient-glow { |
|||
position: absolute; |
|||
border-radius: 50%; |
|||
filter: blur(80px); |
|||
opacity: 0.25; |
|||
pointer-events: none; |
|||
z-index: 0; |
|||
} |
|||
|
|||
.glow-1 { |
|||
width: 350px; |
|||
height: 350px; |
|||
background: #06b6d4; |
|||
top: -50px; |
|||
left: -50px; |
|||
} |
|||
|
|||
.glow-2 { |
|||
width: 400px; |
|||
height: 400px; |
|||
background: #f59e0b; |
|||
bottom: -80px; |
|||
right: -80px; |
|||
} |
|||
|
|||
.login-card { |
|||
position: relative; |
|||
z-index: 1; |
|||
width: 100%; |
|||
max-width: 460px; |
|||
background: var(--card-bg); |
|||
backdrop-filter: blur(12px); |
|||
border-radius: 24px; |
|||
padding: 40px 36px; |
|||
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.3), 0 0 0 1px rgba(255, 255, 255, 0.2); |
|||
animation: slideUp 0.6s cubic-bezier(0.16, 1, 0.3, 1); |
|||
} |
|||
|
|||
@keyframes slideUp { |
|||
from { |
|||
opacity: 0; |
|||
transform: translateY(25px); |
|||
} |
|||
to { |
|||
opacity: 1; |
|||
transform: translateY(0); |
|||
} |
|||
} |
|||
|
|||
.header-branding { |
|||
text-align: center; |
|||
margin-bottom: 28px; |
|||
} |
|||
|
|||
.logo-wrap { |
|||
width: 84px; |
|||
height: 84px; |
|||
margin: 0 auto 16px; |
|||
border-radius: 20px; |
|||
background: #ffffff; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
box-shadow: 0 8px 20px rgba(13, 75, 104, 0.15); |
|||
padding: 10px; |
|||
transition: transform 0.3s ease; |
|||
} |
|||
|
|||
.logo-wrap:hover { |
|||
transform: scale(1.05) rotate(2deg); |
|||
} |
|||
|
|||
.logo-wrap img { |
|||
max-width: 100%; |
|||
max-height: 100%; |
|||
object-fit: contain; |
|||
} |
|||
|
|||
.brand-title-en { |
|||
font-family: 'Outfit', sans-serif; |
|||
font-size: 1.15rem; |
|||
font-weight: 800; |
|||
letter-spacing: 0.8px; |
|||
color: #0d4b68; |
|||
text-transform: uppercase; |
|||
margin-bottom: 2px; |
|||
} |
|||
|
|||
.brand-title-ta { |
|||
font-size: 0.82rem; |
|||
color: #475569; |
|||
font-weight: 600; |
|||
margin-bottom: 12px; |
|||
} |
|||
|
|||
.badge-module { |
|||
display: inline-flex; |
|||
align-items: center; |
|||
gap: 6px; |
|||
padding: 6px 14px; |
|||
background: linear-gradient(135deg, #e0f2fe, #e2e8f0); |
|||
color: #0369a1; |
|||
border: 1px solid #bae6fd; |
|||
border-radius: 30px; |
|||
font-size: 0.78rem; |
|||
font-weight: 700; |
|||
text-transform: uppercase; |
|||
letter-spacing: 0.5px; |
|||
} |
|||
|
|||
.badge-module i { |
|||
color: #0284c7; |
|||
} |
|||
|
|||
.form-title { |
|||
font-family: 'Outfit', sans-serif; |
|||
font-size: 1.4rem; |
|||
font-weight: 700; |
|||
color: #0f172a; |
|||
margin: 18px 0 6px; |
|||
text-align: center; |
|||
} |
|||
|
|||
.form-subtitle { |
|||
font-size: 0.85rem; |
|||
color: #64748b; |
|||
text-align: center; |
|||
margin-bottom: 24px; |
|||
} |
|||
|
|||
.form-floating-custom { |
|||
position: relative; |
|||
margin-bottom: 20px; |
|||
} |
|||
|
|||
.form-floating-custom .input-icon { |
|||
position: absolute; |
|||
left: 16px; |
|||
top: 50%; |
|||
transform: translateY(-50%); |
|||
color: #94a3b8; |
|||
font-size: 1.1rem; |
|||
transition: color 0.3s ease; |
|||
pointer-events: none; |
|||
} |
|||
|
|||
.form-floating-custom input { |
|||
width: 100%; |
|||
height: 52px; |
|||
padding: 12px 16px 12px 46px; |
|||
font-size: 0.92rem; |
|||
color: #1e293b; |
|||
background: #f8fafc; |
|||
border: 1.5px solid #e2e8f0; |
|||
border-radius: 12px; |
|||
outline: none; |
|||
transition: all 0.3s ease; |
|||
} |
|||
|
|||
.form-floating-custom input:focus { |
|||
background: #ffffff; |
|||
border-color: #0284c7; |
|||
box-shadow: 0 0 0 4px rgba(2, 132, 199, 0.12); |
|||
} |
|||
|
|||
.form-floating-custom input:focus + .input-icon { |
|||
color: #0284c7; |
|||
} |
|||
|
|||
.btn-submit { |
|||
width: 100%; |
|||
height: 52px; |
|||
background: linear-gradient(135deg, #0d4b68 0%, #0284c7 100%); |
|||
color: #ffffff; |
|||
border: none; |
|||
border-radius: 12px; |
|||
font-family: 'Outfit', sans-serif; |
|||
font-size: 1rem; |
|||
font-weight: 700; |
|||
letter-spacing: 0.5px; |
|||
cursor: pointer; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
gap: 10px; |
|||
transition: all 0.3s ease; |
|||
box-shadow: 0 8px 20px rgba(13, 75, 104, 0.25); |
|||
margin-top: 10px; |
|||
} |
|||
|
|||
.btn-submit:hover:not(:disabled) { |
|||
background: linear-gradient(135deg, #093448 0%, #0369a1 100%); |
|||
box-shadow: 0 12px 25px rgba(13, 75, 104, 0.35); |
|||
transform: translateY(-2px); |
|||
} |
|||
|
|||
.btn-submit:disabled { |
|||
opacity: 0.7; |
|||
cursor: not-allowed; |
|||
} |
|||
|
|||
#error-box { |
|||
background: #fef2f2; |
|||
border: 1px solid #fecaca; |
|||
color: #b91c1c; |
|||
padding: 12px 16px; |
|||
border-radius: 10px; |
|||
font-size: 0.84rem; |
|||
font-weight: 500; |
|||
margin-bottom: 20px; |
|||
display: none; |
|||
align-items: center; |
|||
gap: 10px; |
|||
animation: shake 0.4s ease; |
|||
} |
|||
|
|||
@keyframes shake { |
|||
0%, 100% { transform: translateX(0); } |
|||
25% { transform: translateX(-5px); } |
|||
75% { transform: translateX(5px); } |
|||
} |
|||
|
|||
.system-badge-footer { |
|||
margin-top: 25px; |
|||
text-align: center; |
|||
font-size: 0.76rem; |
|||
color: #94a3b8; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
gap: 8px; |
|||
} |
|||
|
|||
.system-badge-footer span { |
|||
display: inline-block; |
|||
width: 6px; |
|||
height: 6px; |
|||
background: #22c55e; |
|||
border-radius: 50%; |
|||
box-shadow: 0 0 8px #22c55e; |
|||
} |
|||
|
|||
.back-portal-link { |
|||
display: block; |
|||
text-align: center; |
|||
margin-top: 18px; |
|||
color: #0284c7; |
|||
text-decoration: none; |
|||
font-size: 0.85rem; |
|||
font-weight: 600; |
|||
transition: color 0.2s; |
|||
} |
|||
|
|||
.back-portal-link:hover { |
|||
color: #0369a1; |
|||
text-decoration: underline; |
|||
} |
|||
</style> |
|||
</head> |
|||
|
|||
<body> |
|||
<div class="ambient-glow glow-1"></div> |
|||
<div class="ambient-glow glow-2"></div> |
|||
|
|||
<div class="login-card"> |
|||
<div class="header-branding"> |
|||
<div class="logo-wrap"> |
|||
<img th:src="@{/assets/header-images/gcc1.png}" alt="Greater Chennai Corporation Logo"> |
|||
</div> |
|||
<h2 class="brand-title-en">Greater Chennai Corporation</h2> |
|||
<p class="brand-title-ta">பெருநகர சென்னை மாநகராட்சி</p> |
|||
<div class="badge-module"> |
|||
<i class="fa-solid fa-boxes-packing"></i> |
|||
<span>Rental Management System</span> |
|||
</div> |
|||
</div> |
|||
|
|||
<h3 class="form-title">Portal Sign In</h3> |
|||
<p class="form-subtitle">Work Orders • Requests • Challans • Issue & Return</p> |
|||
|
|||
<div id="error-box"> |
|||
<i class="fa-solid fa-circle-exclamation fs-5"></i> |
|||
<span id="error-text">Invalid username or password!</span> |
|||
</div> |
|||
|
|||
<form id="rentalLoginForm" onsubmit="handleRentalLogin(event)"> |
|||
<div class="form-floating-custom"> |
|||
<input type="text" name="usrName" id="usrName" placeholder="Enter Username / Employee ID" required autocomplete="username"> |
|||
<i class="fa-solid fa-user input-icon"></i> |
|||
</div> |
|||
|
|||
<div class="form-floating-custom"> |
|||
<input type="password" name="usrPass" id="usrPass" placeholder="Enter Password" required autocomplete="current-password"> |
|||
<i class="fa-solid fa-lock input-icon"></i> |
|||
</div> |
|||
|
|||
<button type="submit" id="submit-btn" class="btn-submit"> |
|||
<span>Sign In to Rental System</span> |
|||
<i class="fa-solid fa-arrow-right-to-bracket"></i> |
|||
</button> |
|||
</form> |
|||
|
|||
<a th:href="@{/}" class="back-portal-link"> |
|||
<i class="fa-solid fa-arrow-left me-1"></i> Return to Main GCC Home |
|||
</a> |
|||
|
|||
<div class="system-badge-footer"> |
|||
<span></span> |
|||
<span>GCC IT Cell Secured System • Active Version 2.0</span> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Custom JS --> |
|||
<script th:inline="javascript"> |
|||
const contextPath = /*[[@{/}]]*/ '/'; |
|||
</script> |
|||
|
|||
<script> |
|||
function handleRentalLogin(event) { |
|||
event.preventDefault(); |
|||
|
|||
const errorBox = document.getElementById("error-box"); |
|||
const errorText = document.getElementById("error-text"); |
|||
const submitBtn = document.getElementById("submit-btn"); |
|||
|
|||
errorBox.style.display = "none"; |
|||
submitBtn.disabled = true; |
|||
submitBtn.innerHTML = '<i class="fa-solid fa-circle-notch fa-spin"></i> Authenticating...'; |
|||
|
|||
const username = document.getElementById("usrName").value.trim(); |
|||
const password = document.getElementById("usrPass").value; |
|||
|
|||
const urlParams = new URLSearchParams(); |
|||
urlParams.append('usrName', username); |
|||
urlParams.append('usrPass', password); |
|||
|
|||
// Fetch CSRF tokens if available |
|||
const csrfToken = document.querySelector("meta[name='_csrf']")?.getAttribute("content"); |
|||
const csrfHeader = document.querySelector("meta[name='_csrf_header']")?.getAttribute("content"); |
|||
|
|||
const headers = { |
|||
'Content-Type': 'application/x-www-form-urlencoded' |
|||
}; |
|||
if (csrfToken && csrfHeader) { |
|||
headers[csrfHeader] = csrfToken; |
|||
} |
|||
|
|||
fetch(contextPath + 'gccrentalmanagement/api/login', { |
|||
method: 'POST', |
|||
headers: headers, |
|||
body: urlParams |
|||
}) |
|||
.then(response => response.json()) |
|||
.then(data => { |
|||
if (data.result) { |
|||
sessionStorage.setItem("rental_usrName", data.usrName); |
|||
sessionStorage.setItem("rental_usrRole", data.usrRole || "USER"); |
|||
window.location.href = contextPath + 'gccrentalmanagement/dashboard'; |
|||
} else { |
|||
submitBtn.disabled = false; |
|||
submitBtn.innerHTML = '<span>Sign In to Rental System</span> <i class="fa-solid fa-arrow-right-to-bracket"></i>'; |
|||
errorText.textContent = data.error || "Authentication failed. Check your username and password."; |
|||
errorBox.style.display = "flex"; |
|||
} |
|||
}) |
|||
.catch(err => { |
|||
console.error("Login Error:", err); |
|||
submitBtn.disabled = false; |
|||
submitBtn.innerHTML = '<span>Sign In to Rental System</span> <i class="fa-solid fa-arrow-right-to-bracket"></i>'; |
|||
errorText.textContent = "Network error. Please try again later."; |
|||
errorBox.style.display = "flex"; |
|||
}); |
|||
} |
|||
</script> |
|||
</body> |
|||
|
|||
</html> |
|||
4306
src/main/resources/templates/gcctonermanagement/upload.html
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Write
Preview
Loading…
Cancel
Save
Reference in new issue