package com.gcc_manpower.gccadjustmentmanagement.controller; import java.io.File; import java.util.ArrayList; import java.util.Collections; 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.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; 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.gccadjustmentmanagement.service.AdjustmentService; import com.gcc_manpower.service.AppUserService; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpSession; @Controller @RequestMapping("/gccadjustmentmanagement") public class AdjustmentController { @Autowired private AdjustmentService adjustmentService; @Autowired private AppUserService appUserService; @Autowired private AuthenticationManager authenticationManager; @Value("${adjustment.upload.path:gccadjustmentmanagementfiles}") private String adjustmentUploadPathConfig; @GetMapping({ "", "/", "/dashboard" }) public String viewDashboard(Model model, HttpSession session) { String username = (String) session.getAttribute("adj_usrName"); if (username == null) { return "redirect:/gccadjustmentmanagement/login"; } String usrRole = (String) session.getAttribute("adj_usrRole"); boolean isAdmin = "ADMIN".equalsIgnoreCase(usrRole); model.addAttribute("isLoggedIn", true); model.addAttribute("isAdmin", isAdmin); model.addAttribute("usrName", username); model.addAttribute("curPage", "gccadjustmentmanagement"); return "gccadjustmentmanagement/dashboard"; } @GetMapping("/details") public String viewDetails(Model model, HttpSession session) { String username = (String) session.getAttribute("adj_usrName"); if (username == null) { return "redirect:/gccadjustmentmanagement/login"; } String usrRole = (String) session.getAttribute("adj_usrRole"); boolean isAdmin = "ADMIN".equalsIgnoreCase(usrRole); model.addAttribute("isLoggedIn", true); model.addAttribute("isAdmin", isAdmin); model.addAttribute("usrName", username); model.addAttribute("curPage", "gccadjustmentmanagement"); return "gccadjustmentmanagement/details"; } @GetMapping("/login") public String login(HttpSession session) { return "gccadjustmentmanagement/login"; } @PostMapping("/api/login") @ResponseBody public Map validateLogin( @RequestParam("usrName") String usrName, @RequestParam("usrPass") String usrPass, HttpSession session) { Map 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("adj_usrName", usrName); session.setAttribute("adj_usrRole", role); session.setMaxInactiveInterval(1800); // 30 minutes session timeout response.put("result", true); response.put("usrName", usrName); } 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 logout(HttpSession session, HttpServletRequest request) { SecurityContextHolder.clearContext(); if (session != null) { session.removeAttribute("adj_usrName"); session.removeAttribute("adj_usrRole"); session.invalidate(); } request.getSession(true); return "redirect:/gccadjustmentmanagement/login"; } @GetMapping("/api/advance-types") @ResponseBody public List> getAdvanceTypes(HttpSession session) { if (session.getAttribute("adj_usrName") == null) { return Collections.emptyList(); } return adjustmentService.getAdvanceTypes(); } @GetMapping("/api/fund-types") @ResponseBody public List> getFundTypes(HttpSession session) { if (session.getAttribute("adj_usrName") == null) { return Collections.emptyList(); } return adjustmentService.getFundTypes(); } @GetMapping("/api/file-statuses") @ResponseBody public List> getFileStatuses(HttpSession session) { if (session.getAttribute("adj_usrName") == null) { return Collections.emptyList(); } return adjustmentService.getFileStatusList(); } @GetMapping("/api/list") @ResponseBody public List> getFilesList(HttpSession session) { if (session.getAttribute("adj_usrName") == null) { return Collections.emptyList(); } return adjustmentService.getAllFiles(); } @GetMapping("/api/list-all") @ResponseBody public List> getFilesListIncludingDeleted(HttpSession session) { if (session.getAttribute("adj_usrName") == null) { return Collections.emptyList(); } return adjustmentService.getAllFilesIncludingDeleted(); } @GetMapping("/api/pending/fi-available") @ResponseBody public List> getPendingFIAvailable(HttpSession session) { if (session.getAttribute("adj_usrName") == null) { return Collections.emptyList(); } return adjustmentService.getPendingFinalInvoiceAvailableFiles(); } @GetMapping("/api/pending/fi-not-available") @ResponseBody public List> getPendingFINotAvailable(HttpSession session) { if (session.getAttribute("adj_usrName") == null) { return Collections.emptyList(); } return adjustmentService.getPendingFinalInvoiceNotAvailableFiles(); } @GetMapping("/api/pending/ready-to-close") @ResponseBody public List> getReadyToClose(HttpSession session) { if (session.getAttribute("adj_usrName") == null) { return Collections.emptyList(); } return adjustmentService.getReadyToCloseFiles(); } @PostMapping("/api/save") @ResponseBody public Map saveAdjustment( @RequestParam(value = "id", required = false) Integer id, @RequestParam(value = "vend_name", required = false) String vendName, @RequestParam(value = "fin_year", required = false) String finYear, @RequestParam(value = "subject", required = false) String subject, @RequestParam(value = "adv_type_id", required = false) String advTypeId, @RequestParam(value = "fund_type_id", required = false) String fundTypeId, @RequestParam(value = "bal_amt", required = false) Double balAmt, @RequestParam(value = "file_remark", required = false) String fileRemark, @RequestParam(value = "file_data_num", required = false) String fileDataNum, @RequestParam(value = "pi_amt", required = false) Double piAmt, @RequestParam(value = "pi_file_gen_date", required = false) String piFileGenDate, @RequestParam(value = "fi_amt", required = false) String fiAmt, @RequestParam(value = "fi_file_gen_date", required = false) String fiFileGenDate, @RequestParam(value = "tc_file_gen_date", required = false) String tcFileGenDate, @RequestParam(value = "ejv_num", required = false) String ejvNum, @RequestParam(value = "ejv_num_file_gen_date", required = false) String ejvNumFileGenDate, @RequestParam(value = "as_file_gen_date", required = false) String asFileGenDate, @RequestParam(value = "as_final_file_gen_date", required = false) String asFinalFileGenDate, @RequestParam(value = "ac_code", required = false) String acCode, @RequestParam(value = "file_available_status", required = false) String fileAvailableStatus, @RequestParam(value = "rtgs_date", required = false) String rtgsDate, @RequestParam(value = "dc_completed_date", required = false) String dcCompletedDate, @RequestParam(value = "file", required = false) MultipartFile file, @RequestParam(value = "poFile", required = false) MultipartFile poFile, @RequestParam(value = "dcFile", required = false) MultipartFile dcFile, @RequestParam(value = "irFile", required = false) MultipartFile irFile, @RequestParam(value = "srFile", required = false) MultipartFile srFile, @RequestParam(value = "piFile", required = false) MultipartFile piFile, @RequestParam(value = "fiFile", required = false) MultipartFile fiFile, @RequestParam(value = "tcFile", required = false) MultipartFile tcFile, @RequestParam(value = "rtgsFile", required = false) MultipartFile rtgsFile, @RequestParam(value = "ejvFile", required = false) MultipartFile ejvFile, @RequestParam(value = "asFile", required = false) MultipartFile asFile, @RequestParam(value = "asFinalFile", required = false) MultipartFile asFinalFile, @RequestParam(value = "file_status_id", required = false) Integer fileStatusId, HttpSession session) { Map response = new HashMap<>(); String username = (String) session.getAttribute("adj_usrName"); if (username == null) { response.put("success", false); response.put("error", "Unauthorized access. Please log in."); return response; } try { Map existing = null; if (id != null) { existing = adjustmentService.getAdjustmentFileById(id); if (existing == null) { response.put("success", false); response.put("error", "Record not found."); return response; } } File uploadDir = new File(adjustmentUploadPathConfig).getAbsoluteFile(); if (!uploadDir.exists()) { uploadDir.mkdirs(); } // Save files or keep existing String filePath = saveFile(file, "file", fileDataNum, uploadDir, existing != null ? (String) existing.get("file_path") : null); String poPath = saveFile(poFile, "po", fileDataNum, uploadDir, existing != null ? (String) existing.get("po_file_path") : null); String dcPath = saveFile(dcFile, "dc", fileDataNum, uploadDir, existing != null ? (String) existing.get("dc_file_path") : null); String irPath = saveFile(irFile, "ir", fileDataNum, uploadDir, existing != null ? (String) existing.get("ir_file_path") : null); String srPath = saveFile(srFile, "sr", fileDataNum, uploadDir, existing != null ? (String) existing.get("sr_filepath") : null); String piPath = saveFile(piFile, "pi", fileDataNum, uploadDir, existing != null ? (String) existing.get("pi_file_path") : null); String fiPath = saveFile(fiFile, "fi", fileDataNum, uploadDir, existing != null ? (String) existing.get("fi_file_path") : null); String tcPath = saveFile(tcFile, "tc", fileDataNum, uploadDir, existing != null ? (String) existing.get("tc_file_path") : null); String rtgsPath = saveFile(rtgsFile, "rtgs", fileDataNum, uploadDir, existing != null ? (String) existing.get("rtgs_file_path") : null); String ejvPath = saveFile(ejvFile, "ejv", fileDataNum, uploadDir, existing != null ? (String) existing.get("ejv_num_file_path") : null); String asPath = saveFile(asFile, "as", fileDataNum, uploadDir, existing != null ? (String) existing.get("as_file_path") : null); String asFinalPath = saveFile(asFinalFile, "as_final", fileDataNum, uploadDir, existing != null ? (String) existing.get("as_final_file_path") : null); // Build data map Map data = new HashMap<>(); if (id != null) data.put("id", id); data.put("vend_name", vendName); data.put("fin_year", finYear); data.put("subject", subject); data.put("adv_type_id", advTypeId); data.put("fund_type_id", fundTypeId); data.put("bal_amt", balAmt); data.put("file_remark", fileRemark); data.put("file_data_num", fileDataNum); data.put("pi_amt", piAmt); data.put("pi_file_gen_date", piFileGenDate); data.put("fi_amt", fiAmt); data.put("fi_file_gen_date", fiFileGenDate); data.put("tc_file_gen_date", tcFileGenDate); data.put("ejv_num", ejvNum); data.put("ejv_num_file_gen_date", ejvNumFileGenDate); data.put("as_file_gen_date", asFileGenDate); data.put("as_final_file_gen_date", asFinalFileGenDate); data.put("ac_code", acCode); data.put("file_available_status", fileAvailableStatus); data.put("rtgs_date", rtgsDate); data.put("dc_completed_date", dcCompletedDate); data.put("file_status_id", fileStatusId); // Paths data.put("file_path", filePath); data.put("po_file_path", poPath); data.put("dc_file_path", dcPath); data.put("ir_file_path", irPath); data.put("sr_filepath", srPath); data.put("pi_file_path", piPath); data.put("fi_file_path", fiPath); data.put("tc_file_path", tcPath); data.put("rtgs_file_path", rtgsPath); data.put("ejv_num_file_path", ejvPath); data.put("as_file_path", asPath); data.put("as_final_file_path", asFinalPath); boolean saved = adjustmentService.saveAdjustmentFile(data, username); if (saved) { response.put("success", true); response.put("message", "Adjustment file details saved successfully."); } else { response.put("success", false); response.put("error", "Failed to save details in database."); } } catch (Exception e) { response.put("success", false); response.put("error", "Error occurred: " + e.getMessage()); e.printStackTrace(); } return response; } @PostMapping("/api/delete") @ResponseBody public Map deleteAdjustment( @RequestParam("id") Integer id, @RequestParam(value = "remarks", required = false) String remarks, HttpSession session) { Map response = new HashMap<>(); String username = (String) session.getAttribute("adj_usrName"); if (username == null) { response.put("success", false); response.put("error", "Unauthorized access. Please log in."); return response; } boolean deleted = adjustmentService.deleteAdjustmentFile(id, remarks != null ? remarks : "Deleted by user", username); if (deleted) { response.put("success", true); response.put("message", "Record deleted successfully."); } else { response.put("success", false); response.put("error", "Failed to delete record."); } return response; } @PostMapping("/api/update-ejv") @ResponseBody public Map updateEJV( @RequestParam("id") Integer id, @RequestParam("ejv_num") String ejvNum, @RequestParam(value = "ejvFile", required = false) MultipartFile ejvFile, HttpSession session) { Map response = new HashMap<>(); String username = (String) session.getAttribute("adj_usrName"); if (username == null) { response.put("success", false); response.put("error", "Unauthorized access. Please log in."); return response; } try { Map existing = adjustmentService.getAdjustmentFileById(id); if (existing == null) { response.put("success", false); response.put("error", "Record not found."); return response; } File uploadDir = new File(adjustmentUploadPathConfig).getAbsoluteFile(); if (!uploadDir.exists()) { uploadDir.mkdirs(); } String fileDataNum = (String) existing.get("file_data_num"); String ejvPath = saveFile(ejvFile, "ejv", fileDataNum, uploadDir, existing != null ? (String) existing.get("ejv_num_file_path") : null); boolean updated = adjustmentService.updateEJV(id, ejvNum, ejvPath, username); if (updated) { response.put("success", true); response.put("message", "EJV details updated successfully."); } else { response.put("success", false); response.put("error", "Failed to update EJV details in database."); } } catch (Exception e) { response.put("success", false); response.put("error", "Error occurred: " + e.getMessage()); e.printStackTrace(); } return response; } private String saveFile(MultipartFile f, String category, String fileNum, File dir, String currentPath) throws Exception { if (f == null || f.isEmpty()) { return currentPath; } // Clean fileNum String cleanFileNum = "unknown"; if (fileNum != null && !fileNum.trim().isEmpty()) { // Remove illegal characters, but allow slashes / and \ for hierarchy cleanFileNum = fileNum.trim().replaceAll("[^a-zA-Z0-9.\\/\\\\_-]", "_"); // Normalize path separators to forward slash / cleanFileNum = cleanFileNum.replace('\\', '/'); } // Save files inside the physical "uploads" directory in the project root File projectRoot = new File(".").getAbsoluteFile(); String subPath = "uploads/file-data/" + cleanFileNum + "/" + category.toUpperCase(); File folder = new File(projectRoot, subPath).getAbsoluteFile(); if (!folder.exists()) { folder.mkdirs(); } String orig = f.getOriginalFilename(); String ext = orig != null && orig.lastIndexOf('.') > 0 ? orig.substring(orig.lastIndexOf('.')) : ".pdf"; String cleanName = orig != null ? orig.substring(0, orig.lastIndexOf('.')).replaceAll("[^a-zA-Z0-9.-]", "_") + ext : (category + "_" + System.currentTimeMillis() + ext); File dest = new File(folder, cleanName).getAbsoluteFile(); f.transferTo(dest); return "uploads/file-data/" + cleanFileNum + "/" + category.toUpperCase() + "/" + cleanName; } }