diff --git a/pom.xml b/pom.xml index 4bd30e2..aa8247d 100644 --- a/pom.xml +++ b/pom.xml @@ -43,8 +43,8 @@ spring-boot-starter-jdbc - org.springframework.security - spring-security-crypto + org.springframework.boot + spring-boot-starter-security diff --git a/src/main/java/com/gcc_manpower/config/AppUserDetailsService.java b/src/main/java/com/gcc_manpower/config/AppUserDetailsService.java new file mode 100644 index 0000000..ab5b5b3 --- /dev/null +++ b/src/main/java/com/gcc_manpower/config/AppUserDetailsService.java @@ -0,0 +1,66 @@ +package com.gcc_manpower.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +import javax.sql.DataSource; +import java.util.List; +import java.util.Map; + +@Service +public class AppUserDetailsService implements UserDetailsService { + + private JdbcTemplate jdbcTemplate; + + @Autowired + public void setDataSource(@Qualifier("mysqlManpowerDataSource") DataSource dataSource) { + this.jdbcTemplate = new JdbcTemplate(dataSource); + } + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + String sql = "SELECT usr_name, usr_pass, usr_role, is_active FROM app_user WHERE usr_name = ?"; + List> users; + try { + users = jdbcTemplate.queryForList(sql, username); + } catch (Exception e) { + throw new UsernameNotFoundException("Database error during user retrieval", e); + } + + if (users == null || users.isEmpty()) { + throw new UsernameNotFoundException("Invalid username or password!"); + } + + Map user = users.get(0); + + // Check if user is active + int isActive = 1; + Object activeObj = user.get("is_active"); + if (activeObj instanceof Number) { + isActive = ((Number) activeObj).intValue(); + } else if (activeObj instanceof Boolean) { + isActive = (Boolean) activeObj ? 1 : 0; + } + + if (isActive == 0) { + throw new UsernameNotFoundException("User account is inactive!"); + } + + String password = (String) user.get("usr_pass"); + String role = (String) user.get("usr_role"); + if (role == null) { + role = "USER"; + } + + return User.withUsername(username) + .password(password != null ? password : "") + .roles(role.toUpperCase()) // Will be loaded as authority ROLE_ROLE + .build(); + } +} diff --git a/src/main/java/com/gcc_manpower/config/SecurityConfig.java b/src/main/java/com/gcc_manpower/config/SecurityConfig.java new file mode 100644 index 0000000..c60cceb --- /dev/null +++ b/src/main/java/com/gcc_manpower/config/SecurityConfig.java @@ -0,0 +1,123 @@ +package com.gcc_manpower.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.header.writers.XXssProtectionHeaderWriter; + +@Configuration +@EnableWebSecurity +public class SecurityConfig { + + @Bean + public PasswordEncoder passwordEncoder() { + return new PasswordEncoder() { + private final BCryptPasswordEncoder bcrypt = new BCryptPasswordEncoder(); + + @Override + public String encode(CharSequence rawPassword) { + return bcrypt.encode(rawPassword); + } + + @Override + public boolean matches(CharSequence rawPassword, String dbPassword) { + if (dbPassword != null && dbPassword.startsWith("$2a$")) { + return bcrypt.matches(rawPassword, dbPassword); + } + return rawPassword.toString().equals(dbPassword); + } + }; + } + + @Bean + public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception { + return config.getAuthenticationManager(); + } + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http + // Configure headers for clickjacking and XSS protection + .headers(headers -> headers + .frameOptions(frame -> frame.sameOrigin()) + .xssProtection( + xss -> xss.headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK))) + // Configure URL authorization + .authorizeHttpRequests(auth -> auth + // Allow static resources + .requestMatchers( + "/assets/**", + "/css/**", + "/js/**", + "/images/**", + "/favicon.ico", + "/error") + .permitAll() + // Allow login pages and login API endpoints + .requestMatchers( + "/login", + "/api/val-app-usr-login", + "/gcctonermanagement/login", + "/gcctonermanagement/api/login", + "/gccservicepaymenttracker/login", + "/gccservicepaymenttracker/api/login", + "/gccservicedocuments/login", + "/gccservicedocuments/api/login") + .permitAll() + // Allow logout endpoints + .requestMatchers( + "/usr-logout", + "/gcctonermanagement/logout", + "/gccservicepaymenttracker/logout", + "/gccservicedocuments/logout") + .permitAll() + // Require authentication for all other requests + .anyRequest().authenticated()) + // Configure CSRF protection (ignore CSRF on the login endpoints only) + .csrf(csrf -> csrf + .ignoringRequestMatchers( + "/api/val-app-usr-login", + "/gcctonermanagement/api/login", + "/gccservicepaymenttracker/api/login", + "/gccservicedocuments/api/login")) + // Session management configuration with module-aware invalid session + // redirection + .sessionManagement(session -> session + .invalidSessionStrategy((request, response) -> { + // Create a fresh session so requestedSessionIdValid won't cause endless loop + request.getSession(true); + String requestURI = request.getRequestURI(); + if (requestURI.contains("/gccservicepaymenttracker")) { + response.sendRedirect(request.getContextPath() + "/gccservicepaymenttracker/login"); + } else if (requestURI.contains("/gcctonermanagement")) { + response.sendRedirect(request.getContextPath() + "/gcctonermanagement/login"); + } else if (requestURI.contains("/gccservicedocuments")) { + response.sendRedirect(request.getContextPath() + "/gccservicedocuments/login"); + } else { + response.sendRedirect(request.getContextPath() + "/login"); + } + })) + // Exception handling for unauthenticated requests with module-aware redirection + .exceptionHandling(exceptions -> exceptions + .authenticationEntryPoint((request, response, authException) -> { + String requestURI = request.getRequestURI(); + if (requestURI.contains("/gccservicepaymenttracker")) { + response.sendRedirect(request.getContextPath() + "/gccservicepaymenttracker/login"); + } else if (requestURI.contains("/gcctonermanagement")) { + response.sendRedirect(request.getContextPath() + "/gcctonermanagement/login"); + } else if (requestURI.contains("/gccservicedocuments")) { + response.sendRedirect(request.getContextPath() + "/gccservicedocuments/login"); + } else { + response.sendRedirect(request.getContextPath() + "/login"); + } + })); + + return http.build(); + } +} diff --git a/src/main/java/com/gcc_manpower/controller/HomeController.java b/src/main/java/com/gcc_manpower/controller/HomeController.java index ad4e435..67f0ae1 100644 --- a/src/main/java/com/gcc_manpower/controller/HomeController.java +++ b/src/main/java/com/gcc_manpower/controller/HomeController.java @@ -19,6 +19,13 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.web.multipart.MultipartFile; import java.io.File; +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("/") public class HomeController { @@ -26,6 +33,9 @@ public class HomeController { @Autowired private AppUserService appUserService; + @Autowired + private AuthenticationManager authenticationManager; + @Value("${upload.path:gcc_manpower_uploads}") private String uploadPathConfig; @@ -93,18 +103,29 @@ public class HomeController { @RequestParam("usrPass") String usrPass, HttpSession session) { - Map authResult = appUserService.authenticate(usrName, usrPass); Map response = new HashMap<>(); - if (Boolean.TRUE.equals(authResult.get("success"))) { - session.setAttribute("usrName", authResult.get("usrName")); - session.setAttribute("usrRole", authResult.get("usrRole")); + 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("usrName", usrName); + session.setAttribute("usrRole", role); session.setMaxInactiveInterval(600); // 10 minutes session timeout response.put("result", true); - response.put("usrName", authResult.get("usrName")); - } else { + response.put("usrName", usrName); + } catch (AuthenticationException e) { response.put("result", false); - response.put("error", authResult.get("error")); + response.put("error", e.getMessage() != null ? e.getMessage() : "Invalid username or password!"); } return response; @@ -634,6 +655,7 @@ public class HomeController { @PostMapping("/usr-logout") public String logout(HttpSession session) { + SecurityContextHolder.clearContext(); session.invalidate(); return "redirect:/login"; } diff --git a/src/main/java/com/gcc_manpower/gccservicedocuments/controller/GccServiceDocumentsController.java b/src/main/java/com/gcc_manpower/gccservicedocuments/controller/GccServiceDocumentsController.java index 5ddd71f..dc150a0 100644 --- a/src/main/java/com/gcc_manpower/gccservicedocuments/controller/GccServiceDocumentsController.java +++ b/src/main/java/com/gcc_manpower/gccservicedocuments/controller/GccServiceDocumentsController.java @@ -10,11 +10,19 @@ import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import jakarta.servlet.http.HttpSession; +import jakarta.servlet.http.HttpServletRequest; import java.io.File; import java.util.HashMap; import java.util.List; import java.util.Map; +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("/gccservicedocuments") public class GccServiceDocumentsController { @@ -28,6 +36,9 @@ public class GccServiceDocumentsController { @Autowired private AppUserService appUserService; + @Autowired + private AuthenticationManager authenticationManager; + @Value("${document.upload.path:gccservicedocuments}") private String documentUploadPathConfig; @@ -81,27 +92,45 @@ public class GccServiceDocumentsController { @RequestParam("usrPass") String usrPass, HttpSession session) { - Map authResult = appUserService.authenticate(usrName, usrPass); Map response = new HashMap<>(); - if (Boolean.TRUE.equals(authResult.get("success"))) { - session.setAttribute("doc_usrName", authResult.get("usrName")); - session.setAttribute("doc_usrRole", authResult.get("usrRole")); + 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("doc_usrName", usrName); + session.setAttribute("doc_docRole", role); // keep backward compatibility + session.setAttribute("doc_usrRole", role); session.setMaxInactiveInterval(1800); // 30 minutes session timeout response.put("result", true); - response.put("usrName", authResult.get("usrName")); - } else { + response.put("usrName", usrName); + } catch (AuthenticationException e) { response.put("result", false); - response.put("error", authResult.get("error")); + response.put("error", e.getMessage() != null ? e.getMessage() : "Invalid username or password!"); } return response; } @GetMapping("/logout") - public String logout(HttpSession session) { - session.removeAttribute("doc_usrName"); - session.removeAttribute("doc_usrRole"); + public String logout(HttpSession session, HttpServletRequest request) { + SecurityContextHolder.clearContext(); + if (session != null) { + session.removeAttribute("doc_usrName"); + session.removeAttribute("doc_usrRole"); + session.invalidate(); + } + request.getSession(true); return "redirect:/gccservicedocuments/login"; } diff --git a/src/main/java/com/gcc_manpower/gccservicepaymenttracker/controller/GccServicePaymentTrackerController.java b/src/main/java/com/gcc_manpower/gccservicepaymenttracker/controller/GccServicePaymentTrackerController.java index fb23830..5945854 100644 --- a/src/main/java/com/gcc_manpower/gccservicepaymenttracker/controller/GccServicePaymentTrackerController.java +++ b/src/main/java/com/gcc_manpower/gccservicepaymenttracker/controller/GccServicePaymentTrackerController.java @@ -9,6 +9,7 @@ import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import jakarta.servlet.http.HttpSession; +import jakarta.servlet.http.HttpServletRequest; import org.springframework.http.CacheControl; import org.springframework.http.ResponseEntity; import java.io.File; @@ -16,6 +17,13 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +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("/gccservicepaymenttracker") public class GccServicePaymentTrackerController { @@ -26,6 +34,9 @@ public class GccServicePaymentTrackerController { @Autowired private AppUserService appUserService; + @Autowired + private AuthenticationManager authenticationManager; + @Value("${payment.tracker.upload.path:gccpaymenttrackerfiles}") private String paymentTrackerUploadPathConfig; @@ -50,6 +61,23 @@ public class GccServicePaymentTrackerController { return "gccservicepaymenttracker/dashboard"; } + @GetMapping("/details") + public String viewDetails(HttpSession session, Model model) { + String username = (String) session.getAttribute("pay_usrName"); + if (username == null) { + return "redirect:/gccservicepaymenttracker/login"; + } + String usrRole = (String) session.getAttribute("pay_usrRole"); + boolean isAdmin = "ADMIN".equalsIgnoreCase(usrRole); + + model.addAttribute("isLoggedIn", true); + model.addAttribute("isAdmin", isAdmin); + model.addAttribute("usrName", username); + model.addAttribute("curPage", "gccservicepaymenttracker"); + + return "gccservicepaymenttracker/details"; + } + @GetMapping("/login") public String login(HttpSession session) { return "gccservicepaymenttracker/login"; @@ -62,34 +90,55 @@ public class GccServicePaymentTrackerController { @RequestParam("usrPass") String usrPass, HttpSession session) { - Map authResult = appUserService.authenticate(usrName, usrPass); Map response = new HashMap<>(); - if (Boolean.TRUE.equals(authResult.get("success"))) { - session.setAttribute("pay_usrName", authResult.get("usrName")); - session.setAttribute("pay_usrRole", authResult.get("usrRole")); + 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("pay_usrName", usrName); + session.setAttribute("pay_usrRole", role); session.setMaxInactiveInterval(1800); // 30 minutes session timeout response.put("result", true); - response.put("usrName", authResult.get("usrName")); - } else { + response.put("usrName", usrName); + } catch (AuthenticationException e) { response.put("result", false); - response.put("error", authResult.get("error")); + response.put("error", e.getMessage() != null ? e.getMessage() : "Invalid username or password!"); } return response; } @PostMapping("/logout") - public String logout(HttpSession session) { - session.removeAttribute("pay_usrName"); - session.removeAttribute("pay_usrRole"); + public String logout(HttpSession session, HttpServletRequest request) { + SecurityContextHolder.clearContext(); + if (session != null) { + session.removeAttribute("pay_usrName"); + session.removeAttribute("pay_usrRole"); + session.invalidate(); + } + request.getSession(true); return "redirect:/gccservicepaymenttracker/login"; } @GetMapping("/logout") - public String logoutGet(HttpSession session) { - session.removeAttribute("pay_usrName"); - session.removeAttribute("pay_usrRole"); + public String logoutGet(HttpSession session, HttpServletRequest request) { + SecurityContextHolder.clearContext(); + if (session != null) { + session.removeAttribute("pay_usrName"); + session.removeAttribute("pay_usrRole"); + session.invalidate(); + } + request.getSession(true); return "redirect:/gccservicepaymenttracker/login"; } diff --git a/src/main/java/com/gcc_manpower/gcctonermanagement/controller/TonerController.java b/src/main/java/com/gcc_manpower/gcctonermanagement/controller/TonerController.java index 4751d63..699f342 100644 --- a/src/main/java/com/gcc_manpower/gcctonermanagement/controller/TonerController.java +++ b/src/main/java/com/gcc_manpower/gcctonermanagement/controller/TonerController.java @@ -18,8 +18,15 @@ import org.springframework.web.multipart.MultipartFile; import java.io.File; import com.gcc_manpower.gcctonermanagement.service.TonerService; 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("/gcctonermanagement") @@ -31,6 +38,9 @@ public class TonerController { @Autowired private TonerService tonerService; + @Autowired + private AuthenticationManager authenticationManager; + @Value("${toner.upload.path:gcctonermanagementfiles}") private String tonerUploadPathConfig; @@ -68,27 +78,44 @@ public class TonerController { @RequestParam("usrPass") String usrPass, HttpSession session) { - Map authResult = appUserService.authenticate(usrName, usrPass); Map response = new HashMap<>(); - if (Boolean.TRUE.equals(authResult.get("success"))) { - session.setAttribute("toner_usrName", authResult.get("usrName")); - session.setAttribute("toner_usrRole", authResult.get("usrRole")); + 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("toner_usrName", usrName); + session.setAttribute("toner_usrRole", role); session.setMaxInactiveInterval(1800); // 30 minutes session timeout response.put("result", true); - response.put("usrName", authResult.get("usrName")); - } else { + response.put("usrName", usrName); + } catch (AuthenticationException e) { response.put("result", false); - response.put("error", authResult.get("error")); + response.put("error", e.getMessage() != null ? e.getMessage() : "Invalid username or password!"); } return response; } @GetMapping("/logout") - public String logoutGet(HttpSession session) { - session.removeAttribute("toner_usrName"); - session.removeAttribute("toner_usrRole"); + public String logoutGet(HttpSession session, HttpServletRequest request) { + SecurityContextHolder.clearContext(); + if (session != null) { + session.removeAttribute("toner_usrName"); + session.removeAttribute("toner_usrRole"); + session.invalidate(); + } + request.getSession(true); return "redirect:/gcctonermanagement/login"; } @@ -286,6 +313,24 @@ public class TonerController { return tonerService.getPendingRequests(); } + @GetMapping("/api/inward/list") + @ResponseBody + public List> getInwardListData(HttpSession session) { + if (session.getAttribute("toner_usrName") == null) { + return java.util.Collections.emptyList(); + } + return tonerService.getInwardHistory(); + } + + @GetMapping("/api/requests/list") + @ResponseBody + public List> getUserRequestsListData(HttpSession session) { + if (session.getAttribute("toner_usrName") == null) { + return java.util.Collections.emptyList(); + } + return tonerService.getAllUserRequests(); + } + @GetMapping("/api/outward/list") @ResponseBody public List> getOutwardListData(HttpSession session) { diff --git a/src/main/java/com/gcc_manpower/gcctonermanagement/service/TonerService.java b/src/main/java/com/gcc_manpower/gcctonermanagement/service/TonerService.java index 548616b..fda9cd5 100644 --- a/src/main/java/com/gcc_manpower/gcctonermanagement/service/TonerService.java +++ b/src/main/java/com/gcc_manpower/gcctonermanagement/service/TonerService.java @@ -224,12 +224,45 @@ public class TonerService { } } + public List> getInwardHistory() { + String sql = "SELECT s.id, s.company_name, s.qty_registered, s.dc_upload, s.cdate, s.order_by, " + + "p.printer_name, t.model_name " + + "FROM stock_register_details s " + + "LEFT JOIN printer_model_list p ON CAST(s.pid AS SIGNED) = p.id " + + "LEFT JOIN toner_model_list t ON CAST(s.tid AS SIGNED) = t.id " + + "WHERE s.is_active = 1 AND s.is_delete = 0 " + + "ORDER BY s.id DESC"; + try { + return jdbcTemplate.queryForList(sql); + } catch (Exception e) { + System.err.println("Error fetching inward history: " + e.getMessage()); + return new ArrayList<>(); + } + } + + public List> getAllUserRequests() { + String sql = "SELECT r.id, r.req_no, r.itcell_ref_no, r.dept_id, r.qty_requested, r.qty_delivered, " + + "r.user_request_upload, r.cdate, r.updated_date, r.updated_by, " + + "p.printer_name, t.model_name " + + "FROM department_requested_details r " + + "LEFT JOIN printer_model_list p ON CAST(r.pid AS SIGNED) = p.id " + + "LEFT JOIN toner_model_list t ON CAST(r.tid AS SIGNED) = t.id " + + "WHERE r.is_active = 1 AND r.is_delete = 0 " + + "ORDER BY r.id DESC"; + try { + return jdbcTemplate.queryForList(sql); + } catch (Exception e) { + System.err.println("Error fetching user requests: " + e.getMessage()); + return new ArrayList<>(); + } + } + public List> getOutwardHistory() { - String sql = "SELECT r.id, r.req_no, r.itcell_ref_no, r.dept_id, r.qty_requested, r.qty_delivered, r.final_delivered_upload, r.updated_date, " + + String sql = "SELECT r.id, r.req_no, r.itcell_ref_no, r.dept_id, r.qty_requested, r.qty_delivered, r.final_delivered_upload, r.user_request_upload, r.cdate, r.updated_date, " + "p.printer_name, t.model_name " + "FROM department_requested_details r " + - "LEFT JOIN printer_model_list p ON r.pid = p.id " + - "LEFT JOIN toner_model_list t ON r.tid = t.id " + + "LEFT JOIN printer_model_list p ON CAST(r.pid AS SIGNED) = p.id " + + "LEFT JOIN toner_model_list t ON CAST(r.tid AS SIGNED) = t.id " + "WHERE r.is_active = 1 AND r.is_delete = 0 " + "AND r.qty_delivered IS NOT NULL AND CAST(r.qty_delivered AS SIGNED) > 0 " + "ORDER BY r.updated_date DESC"; @@ -241,3 +274,4 @@ public class TonerService { } } } + diff --git a/src/main/resources/templates/gccservicepaymenttracker/dashboard.html b/src/main/resources/templates/gccservicepaymenttracker/dashboard.html index b35a7aa..047177b 100644 --- a/src/main/resources/templates/gccservicepaymenttracker/dashboard.html +++ b/src/main/resources/templates/gccservicepaymenttracker/dashboard.html @@ -1632,11 +1632,7 @@ Delete Record - - - - - + - - - - Type - Filter - - - - - + + + Type Filter + + + + + + + Status Filter + + + + + + + Type of Bill + - All Types - - - - Status - Filter - - - - - + + Status + - All Statuses - - - - Vendor Filter - + + Vendor + - All Vendors - - - - Search: - + + Search Table + - - - - Export to Excel + + + + 0 Records + + + + Export Excel - - - - + + Sr. No. - Received Date - Invoice Date - Physical File No. - eFile No./ Receipt No. - Subject - Type of File - Vendor Name - Amount - Age of Bill (Days) - Status + Received Date + Invoice Date + Department + Physical File No. + eFile No./ Receipt No. + Subject + Type of File + Vendor Name + Amount + Age of Bill (Days) + Status Remarks - Last Updated Date + Last Updated Date Last Updated By Actions - - + No Records Found No payment tracking records match the active criteria. @@ -1751,6 +1728,10 @@ + --> + + + { const cat = getCategoryCode(row.resolved_type || row.type); if (cat in counts) { counts[cat]++; - } else { - counts['status_not_updated']++; } }); @@ -3570,8 +3561,7 @@ { key: 'sd', label: 'Security Deposit', color: '#1e40af', textLight: '#dbeafe', bgLight: '#eff6ff' }, { key: 'emd', label: 'EMD', color: '#6b21a8', textLight: '#f3e8ff', bgLight: '#faf5ff' }, { key: 'asd', label: 'ASD', color: '#9a3412', textLight: '#ffedd5', bgLight: '#fff7ed' }, - { key: 'agreement', label: 'Agreement', color: '#9d174d', textLight: '#fce7f3', bgLight: '#fdf2f8' }, - { key: 'status_not_updated', label: 'Type Not Updated', color: '#374151', textLight: '#f3f4f6', bgLight: '#f9fafb' } + { key: 'agreement', label: 'Agreement', color: '#9d174d', textLight: '#fce7f3', bgLight: '#fdf2f8' } ]; let html = ''; diff --git a/src/main/resources/templates/gccservicepaymenttracker/details.html b/src/main/resources/templates/gccservicepaymenttracker/details.html new file mode 100644 index 0000000..b750192 --- /dev/null +++ b/src/main/resources/templates/gccservicepaymenttracker/details.html @@ -0,0 +1,2239 @@ + + + + + + + + Count Details - GCC Service Payment Tracker + + + + + + + + + + + + + + + + + + + + + + + + + + + GCC Service Payment Tracker - Details View + + + + Back to Dashboard + + + + + + + + + + + + + Count Details + TYPE: ALL TYPES + + + + Export to Excel + + + Deleted Records + + + Add Payment Tracking Record + + + + + + + + Show + + 15 + 20 + 50 + 100 + All + + entries + + + Search: + + + + + + + + + + Type Filter + + + + + + + + Status Filter + + + + + + + + + + + Type of Bill + + - All Types - + + + + Status + + - All Statuses - + + + + Vendor + + - All Vendors - + + + + + + + + + + + + SR.NO. + + RECEIVEDDATE + + INVOICEDATE + PHYSICALFILE NO. + EFILE NO./RECEIPT NO. + SUBJECT + TYPE OFFILE + VENDORNAME + + AMOUNT + + AGE OFBILL(DAYS) + STATUS + REMARKS + + LASTUPDATED AT + LAST UPDATEDBY + ACTIONS + + + + + Loading details data... + + + + + + + + + Showing 0 to 0 of 0 entries + + + Previous + Page 1 + Next + + + + + + + + + + + + + + Add/Edit Record + + + + + + + + + + Received + Date * + + + + + Type * + + + + + Vendor + Name * + + -- Select Vendor -- + -- Write-in custom vendor -- + + + + + + Subject * + + + + + Amount * + + + + + Invoice + No + + + + + Receipt + No + + + + + Invoice + Date + + + + + Physical File No + + + + + Status * + + + + + PDF Attachment + (Optional) + + + Current Document: + + View PDF + + + + + + Remarks + + + + + + Cancel + + Save Record + + + + + + + + + + + + + + + Payment Record Update History + + + + + + + + + S.NO + RECEIVEDDATE + INVOICEDATE + SUBJECT + TYPE + VENDORNAME + AMOUNT + STATUS + REMARKS + LASTUPDATED AT + LAST UPDATEDBY + ACTIONS + + + + + + + + + No update history found for this record. + + + + + + + + + + + + + + Confirm Delete + + + + + Are you sure you want to delete this payment tracking record? + + Remarks / Reason for Deletion * + + + + + + + + + + + + + + + Deleted Payment Records + + + + + + + + + SR.NO. + RECEIVEDDATE + INVOICEDATE + PHYSICALFILE NO. + EFILE NO./RECEIPT NO. + SUBJECT + TYPE OFFILE + VENDORNAME + AMOUNT + AGE OFBILL(DAYS) + STATUS + DELETIONREMARKS + DELETEDDATE + DELETEDBY + ACTIONS + + + + + + + + + No Deleted Records + No deleted payment tracking records found in the database. + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/gcctonermanagement/upload.html b/src/main/resources/templates/gcctonermanagement/upload.html index 05ebf17..9b70be9 100644 --- a/src/main/resources/templates/gcctonermanagement/upload.html +++ b/src/main/resources/templates/gcctonermanagement/upload.html @@ -34,6 +34,9 @@ + + +
No payment tracking records match the active criteria.
No update history found for this record.
Are you sure you want to delete this payment tracking record?
No deleted payment tracking records found in the database.