diff --git a/src/main/java/com/gcc_manpower/config/DataSourceConfig.java b/src/main/java/com/gcc_manpower/config/DataSourceConfig.java index 22ae13f..baa0aae 100644 --- a/src/main/java/com/gcc_manpower/config/DataSourceConfig.java +++ b/src/main/java/com/gcc_manpower/config/DataSourceConfig.java @@ -10,12 +10,13 @@ import javax.sql.DataSource; @EnableTransactionManagement public class DataSourceConfig { - // private static String host = "localhost:3306"; - // private static String dbpassword = "root"; + private static String host = "localhost:3306"; + private static String dbpassword = "root"; // AWS - private static String host = "gcc-facial-db-instance-1.cf48eqcciziq.ap-south-1.rds.amazonaws.com:3306"; - private static String dbpassword = "gcc-facial-password"; + // private static String host = + // "gcc-facial-db-instance-1.cf48eqcciziq.ap-south-1.rds.amazonaws.com:3306"; + // private static String dbpassword = "gcc-facial-password"; @Bean(name = "mysqlManpowerDataSource") public DataSource mysqlManpowerDataSource() { @@ -36,4 +37,14 @@ public class DataSourceConfig { dataSource.setPassword(dbpassword); return dataSource; } + + @Bean(name = "mysqlPaymentTrackingServiceDataSource") + public DataSource mysqlPaymentTrackingServiceDataSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); + dataSource.setUrl("jdbc:mysql://" + host + "/gccpayment_processing_tracker"); + dataSource.setUsername("root"); + dataSource.setPassword(dbpassword); + return dataSource; + } } diff --git a/src/main/java/com/gcc_manpower/config/WebConfig.java b/src/main/java/com/gcc_manpower/config/WebConfig.java index bd9a8b2..5436af3 100644 --- a/src/main/java/com/gcc_manpower/config/WebConfig.java +++ b/src/main/java/com/gcc_manpower/config/WebConfig.java @@ -9,24 +9,35 @@ import java.nio.file.Paths; @Configuration public class WebConfig implements WebMvcConfigurer { - @Value("${upload.path:gcc_manpower_uploads}") - private String uploadPathConfig; - - @Value("${document.upload.path:gccservicedocuments}") - private String documentUploadPathConfig; - - @Override - public void addResourceHandlers(ResourceHandlerRegistry registry) { - // Resolve absolute path (supports both relative and absolute paths) - String uploadPath = Paths.get(uploadPathConfig).toAbsolutePath().toUri().toString(); - - // Map URL path /gcc_manpower_uploads/** to the configured folder path - registry.addResourceHandler("/gcc_manpower_uploads/**") - .addResourceLocations(uploadPath); - - // Map URL path /gccservicedocuments/files/** to the configured document folder path - String docUploadPath = Paths.get(documentUploadPathConfig).toAbsolutePath().toUri().toString(); - registry.addResourceHandler("/gccservicedocuments/files/**") - .addResourceLocations(docUploadPath); - } + @Value("${upload.path:gcc_manpower_uploads}") + private String uploadPathConfig; + + @Value("${document.upload.path:gccservicedocuments}") + private String documentUploadPathConfig; + + @Value("${payment.tracker.upload.path:gccpaymenttrackerfiles}") + private String paymentTrackerUploadPathConfig; + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + // Resolve absolute path (supports both relative and absolute paths) + String uploadPath = Paths.get(uploadPathConfig).toAbsolutePath().toUri().toString(); + + // Map URL path /gcc_manpower_uploads/** to the configured folder path + registry.addResourceHandler("/gcc_manpower_uploads/**") + .addResourceLocations(uploadPath); + + // Map URL path /gccservicedocuments/files/** to the configured document folder + // path + String docUploadPath = Paths.get(documentUploadPathConfig).toAbsolutePath().toUri().toString(); + registry.addResourceHandler("/gccservicedocuments/files/**") + .addResourceLocations(docUploadPath); + + // Map URL path /gccpaymenttrackerfiles/** to the configured payment tracker + // folder + String trackerUploadPath = Paths.get(paymentTrackerUploadPathConfig).toAbsolutePath().toUri() + .toString(); + registry.addResourceHandler("/gccpaymenttrackerfiles/**") + .addResourceLocations(trackerUploadPath); + } } diff --git a/src/main/java/com/gcc_manpower/controller/GccServiceDocumentController.java b/src/main/java/com/gcc_manpower/gccservicedocuments/controller/GccServiceDocumentsController.java similarity index 91% rename from src/main/java/com/gcc_manpower/controller/GccServiceDocumentController.java rename to src/main/java/com/gcc_manpower/gccservicedocuments/controller/GccServiceDocumentsController.java index 480a006..92cdd38 100644 --- a/src/main/java/com/gcc_manpower/controller/GccServiceDocumentController.java +++ b/src/main/java/com/gcc_manpower/gccservicedocuments/controller/GccServiceDocumentsController.java @@ -1,6 +1,7 @@ -package com.gcc_manpower.controller; +package com.gcc_manpower.gccservicedocuments.controller; -import com.gcc_manpower.service.GccServiceDocumentService; +import com.gcc_manpower.gccservicedocuments.service.GccServiceDocumentsService; +import com.gcc_manpower.gccservicedocuments.service.VideoCompressionService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; @@ -15,13 +16,13 @@ import java.util.Map; @Controller @RequestMapping("/gccservicedocuments") -public class GccServiceDocumentController { +public class GccServiceDocumentsController { @Autowired - private GccServiceDocumentService documentService; + private GccServiceDocumentsService documentService; @Autowired - private com.gcc_manpower.service.VideoCompressionService videoCompressionService; + private VideoCompressionService videoCompressionService; @Value("${document.upload.path:gccservicedocuments}") private String documentUploadPathConfig; @@ -62,9 +63,9 @@ public class GccServiceDocumentController { @GetMapping("/api/list") @ResponseBody public List> listDocuments( - @RequestParam(value = "category", required = false) String category, - @RequestParam(value = "fromDate", required = false) String fromDate, - @RequestParam(value = "toDate", required = false) String toDate) { + @RequestParam(value = "category", required = false) String category, + @RequestParam(value = "fromDate", required = false) String fromDate, + @RequestParam(value = "toDate", required = false) String toDate) { return documentService.searchDocuments(category, fromDate, toDate); } diff --git a/src/main/java/com/gcc_manpower/service/GccServiceDocumentService.java b/src/main/java/com/gcc_manpower/gccservicedocuments/service/GccServiceDocumentsService.java similarity index 98% rename from src/main/java/com/gcc_manpower/service/GccServiceDocumentService.java rename to src/main/java/com/gcc_manpower/gccservicedocuments/service/GccServiceDocumentsService.java index 5cd622d..e076bf7 100644 --- a/src/main/java/com/gcc_manpower/service/GccServiceDocumentService.java +++ b/src/main/java/com/gcc_manpower/gccservicedocuments/service/GccServiceDocumentsService.java @@ -1,4 +1,4 @@ -package com.gcc_manpower.service; +package com.gcc_manpower.gccservicedocuments.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -11,7 +11,7 @@ import java.util.List; import java.util.Map; @Service -public class GccServiceDocumentService { +public class GccServiceDocumentsService { private JdbcTemplate jdbcTemplate; diff --git a/src/main/java/com/gcc_manpower/service/VideoCompressionService.java b/src/main/java/com/gcc_manpower/gccservicedocuments/service/VideoCompressionService.java similarity index 93% rename from src/main/java/com/gcc_manpower/service/VideoCompressionService.java rename to src/main/java/com/gcc_manpower/gccservicedocuments/service/VideoCompressionService.java index 4bedec9..155d4c2 100644 --- a/src/main/java/com/gcc_manpower/service/VideoCompressionService.java +++ b/src/main/java/com/gcc_manpower/gccservicedocuments/service/VideoCompressionService.java @@ -1,4 +1,4 @@ -package com.gcc_manpower.service; +package com.gcc_manpower.gccservicedocuments.service; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; @@ -27,10 +27,12 @@ public class VideoCompressionService { String originalPath = originalFile.getAbsolutePath(); long originalSize = originalFile.length(); - LOGGER.info("Starting background video compression for file: " + originalPath + " (Size: " + (originalSize / (1024 * 1024)) + " MB)"); + LOGGER.info("Starting background video compression for file: " + originalPath + " (Size: " + + (originalSize / (1024 * 1024)) + " MB)"); // Create a temporary file in the same directory for the compressed output - File tempFile = new File(originalFile.getParentFile(), "temp_" + System.currentTimeMillis() + "_" + originalFile.getName()); + File tempFile = new File(originalFile.getParentFile(), + "temp_" + System.currentTimeMillis() + "_" + originalFile.getName()); try { // Read input file details @@ -64,7 +66,7 @@ public class VideoCompressionService { // Replace original file with compressed file if successful if (tempFile.exists() && tempFile.length() > 0) { long compressedSize = tempFile.length(); - + // Delete original file boolean deletedOriginal = originalFile.delete(); if (!deletedOriginal) { diff --git a/src/main/java/com/gcc_manpower/gccservicepaymenttracker/controller/GccServicePaymentTrackerController.java b/src/main/java/com/gcc_manpower/gccservicepaymenttracker/controller/GccServicePaymentTrackerController.java new file mode 100644 index 0000000..758acb3 --- /dev/null +++ b/src/main/java/com/gcc_manpower/gccservicepaymenttracker/controller/GccServicePaymentTrackerController.java @@ -0,0 +1,260 @@ +package com.gcc_manpower.gccservicepaymenttracker.controller; + +import com.gcc_manpower.gccservicepaymenttracker.service.GccServicePaymentTrackerService; +import com.gcc_manpower.service.AppUserService; +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.*; +import org.springframework.web.multipart.MultipartFile; +import jakarta.servlet.http.HttpSession; +import org.springframework.http.CacheControl; +import org.springframework.http.ResponseEntity; +import java.io.File; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Controller +@RequestMapping("/gccservicepaymenttracker") +public class GccServicePaymentTrackerController { + + @Autowired + private GccServicePaymentTrackerService paymentTrackerService; + + @Autowired + private AppUserService appUserService; + + @Value("${payment.tracker.upload.path:gccpaymenttrackerfiles}") + private String paymentTrackerUploadPathConfig; + + @GetMapping({ "", "/", "/dashboard" }) + public String viewDashboard(Model model, HttpSession session) { + String username = (String) session.getAttribute("usrName"); + if (username == null) { + return "redirect:/gccservicepaymenttracker/login"; + } + + String usrRole = (String) session.getAttribute("usrRole"); + boolean isAdmin = "ADMIN".equalsIgnoreCase(usrRole); + + List> vendorDetails = appUserService.getVendorDetailsWithCounts(); + + model.addAttribute("isLoggedIn", true); + model.addAttribute("isAdmin", isAdmin); + model.addAttribute("usrName", username); + model.addAttribute("curPage", "gccservicepaymenttracker"); + model.addAttribute("vendorDetails", vendorDetails); + + return "gccservicepaymenttracker/dashboard"; + } + + @GetMapping("/login") + public String login(HttpSession session) { + if (session.getAttribute("usrName") != null) { + return "redirect:/gccservicepaymenttracker/dashboard"; + } + return "gccservicepaymenttracker/login"; + } + + @PostMapping("/api/login") + @ResponseBody + public Map validateLogin( + @RequestParam("usrName") String usrName, + @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")); + session.setMaxInactiveInterval(1800); // 30 minutes session timeout + response.put("result", true); + response.put("usrName", authResult.get("usrName")); + } else { + response.put("result", false); + response.put("error", authResult.get("error")); + } + + return response; + } + + @PostMapping("/logout") + public String logout(HttpSession session) { + session.removeAttribute("usrName"); + session.removeAttribute("usrRole"); + session.invalidate(); + return "redirect:/gccservicepaymenttracker/login"; + } + + @GetMapping("/logout") + public String logoutGet(HttpSession session) { + session.removeAttribute("usrName"); + session.removeAttribute("usrRole"); + session.invalidate(); + return "redirect:/gccservicepaymenttracker/login"; + } + + @GetMapping("/api/counts") + @ResponseBody + public ResponseEntity> getCounts() { + return ResponseEntity.ok() + .cacheControl(CacheControl.noCache().mustRevalidate()) + .body(paymentTrackerService.getCountsByCategory()); + } + + @GetMapping("/api/list") + @ResponseBody + public ResponseEntity>> listDetails( + @RequestParam(value = "category", required = false) String category, + @RequestParam(value = "fromDate", required = false) String fromDate, + @RequestParam(value = "toDate", required = false) String toDate, + @RequestParam(value = "status", required = false) String status) { + List> details = paymentTrackerService.searchDetails(category, fromDate, toDate, status); + return ResponseEntity.ok() + .cacheControl(CacheControl.noCache().mustRevalidate()) + .body(details); + } + + @PostMapping("/api/save") + @ResponseBody + public Map saveDetail( + @RequestBody Map payload, + HttpSession session) { + + Map response = new HashMap<>(); + String username = (String) session.getAttribute("usrName"); + if (username == null) { + response.put("success", false); + response.put("error", "Unauthorized access! Please log in."); + return response; + } + + String usrRole = (String) session.getAttribute("usrRole"); + if (!"ADMIN".equalsIgnoreCase(usrRole)) { + response.put("success", false); + response.put("error", "Access denied! Only admins can save or update records."); + return response; + } + + try { + boolean saved = paymentTrackerService.saveOrUpdateDetail(payload); + response.put("success", saved); + if (!saved) { + response.put("error", "Failed to save details to database."); + } + } catch (Exception e) { + response.put("success", false); + response.put("error", "Error: " + e.getMessage()); + } + + return response; + } + + @PostMapping("/api/delete") + @ResponseBody + public Map deleteDetail( + @RequestParam("id") int id, + HttpSession session) { + + Map response = new HashMap<>(); + String username = (String) session.getAttribute("usrName"); + if (username == null) { + response.put("success", false); + response.put("error", "Unauthorized access! Please log in."); + return response; + } + + String usrRole = (String) session.getAttribute("usrRole"); + if (!"ADMIN".equalsIgnoreCase(usrRole)) { + response.put("success", false); + response.put("error", "Access denied! Only admins can delete records."); + return response; + } + + try { + boolean deleted = paymentTrackerService.deleteDetail(id); + response.put("success", deleted); + if (!deleted) { + response.put("error", "Failed to delete record."); + } + } catch (Exception e) { + response.put("success", false); + response.put("error", "Error: " + e.getMessage()); + } + + return response; + } + + @PostMapping("/api/upload-pdf") + @ResponseBody + public Map uploadPdf( + @RequestParam("file") MultipartFile file, + HttpSession session) { + Map response = new HashMap<>(); + String username = (String) session.getAttribute("usrName"); + if (username == null) { + response.put("success", false); + response.put("error", "Unauthorized access! Please log in."); + return response; + } + + String usrRole = (String) session.getAttribute("usrRole"); + if (!"ADMIN".equalsIgnoreCase(usrRole)) { + response.put("success", false); + response.put("error", "Access denied! Only admins can upload files."); + return response; + } + + if (file.isEmpty()) { + response.put("success", false); + response.put("error", "Please select a file to upload."); + return response; + } + + try { + File uploadDir = new File(paymentTrackerUploadPathConfig).getAbsoluteFile(); + if (!uploadDir.exists()) { + uploadDir.mkdirs(); + } + + String originalFilename = file.getOriginalFilename(); + String nameWithoutExt = "pdf"; + String ext = ".pdf"; + if (originalFilename != null && originalFilename.contains(".")) { + int dotIdx = originalFilename.lastIndexOf("."); + nameWithoutExt = originalFilename.substring(0, dotIdx); + ext = originalFilename.substring(dotIdx); + } + nameWithoutExt = nameWithoutExt.replaceAll("[^a-zA-Z0-9-_]", "_"); + String savedFilename = nameWithoutExt + "_" + System.currentTimeMillis() + ext; + + File destFile = new File(uploadDir, savedFilename).getAbsoluteFile(); + file.transferTo(destFile); + + String fileWebUrl = "/gccpaymenttrackerfiles/" + savedFilename; + response.put("success", true); + response.put("filePath", fileWebUrl); + } catch (Exception e) { + response.put("success", false); + response.put("error", "File upload failed: " + e.getMessage()); + } + + return response; + } + + @GetMapping("/api/types") + @ResponseBody + public List> getActiveTypes() { + return paymentTrackerService.getActiveTypes(); + } + + @GetMapping("/api/vendors") + @ResponseBody + public List> getActiveVendors() { + return paymentTrackerService.getActiveVendors(); + } +} diff --git a/src/main/java/com/gcc_manpower/gccservicepaymenttracker/service/GccServicePaymentTrackerService.java b/src/main/java/com/gcc_manpower/gccservicepaymenttracker/service/GccServicePaymentTrackerService.java new file mode 100644 index 0000000..7ca9c71 --- /dev/null +++ b/src/main/java/com/gcc_manpower/gccservicepaymenttracker/service/GccServicePaymentTrackerService.java @@ -0,0 +1,285 @@ +package com.gcc_manpower.gccservicepaymenttracker.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Service; +import javax.sql.DataSource; +import jakarta.annotation.PostConstruct; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +public class GccServicePaymentTrackerService { + + private JdbcTemplate jdbcTemplate; + + @Autowired + public void setDataSource(@Qualifier("mysqlPaymentTrackingServiceDataSource") DataSource dataSource) { + this.jdbcTemplate = new JdbcTemplate(dataSource); + } + + public Map getCountsByCategory() { + Map counts = new HashMap<>(); + counts.put("sd", 0); + counts.put("tax invoice", 0); + counts.put("emd", 0); + counts.put("bank guarantee", 0); + counts.put("delivery chellan", 0); + counts.put("asd", 0); + counts.put("agreement", 0); + + String sql = "SELECT " + + "CASE WHEN p.type REGEXP '^[0-9]+$' THEN t.type_name ELSE p.type END as type_resolved, " + + "COUNT(*) as cnt " + + "FROM payment_tracking_details p " + + "LEFT JOIN type_list t ON p.type REGEXP '^[0-9]+$' AND t.id = p.type " + + "WHERE p.is_active = 1 AND p.is_delete = 0 " + + "GROUP BY type_resolved"; + + try { + List> rows = jdbcTemplate.queryForList(sql); + for (Map row : rows) { + String type = String.valueOf(row.get("type_resolved")).toLowerCase().trim(); + Number countNum = (Number) row.get("cnt"); + int count = countNum != null ? countNum.intValue() : 0; + + // Map database values back to categories + if (type.equals("asd") || type.contains("asd") || type.contains("additional security")) { + counts.put("asd", counts.getOrDefault("asd", 0) + count); + } else if (type.equals("agreement") || type.contains("agreement")) { + counts.put("agreement", counts.getOrDefault("agreement", 0) + count); + } else if (type.equals("sd") || type.contains("security")) { + counts.put("sd", counts.getOrDefault("sd", 0) + count); + } else if (type.contains("invoice") || type.contains("bill")) { + counts.put("tax invoice", counts.getOrDefault("tax invoice", 0) + count); + } else if (type.equals("emd")) { + counts.put("emd", counts.getOrDefault("emd", 0) + count); + } else if (type.contains("guarantee") || type.contains("bg")) { + counts.put("bank guarantee", counts.getOrDefault("bank guarantee", 0) + count); + } else if (type.contains("chellan") || type.contains("challan") || type.contains("dc")) { + counts.put("delivery chellan", counts.getOrDefault("delivery chellan", 0) + count); + } + } + } catch (Exception e) { + System.err.println("Error getting category counts: " + e.getMessage()); + } + return counts; + } + + public List> searchDetails(String type, String fromDate, String toDate, String status) { + StringBuilder sql = new StringBuilder( + "SELECT p.*, " + + "t.type_name as resolved_type, " + + "v.vendor_name as resolved_vendor " + + "FROM payment_tracking_details p " + + "LEFT JOIN type_list t ON p.type REGEXP '^[0-9]+$' AND t.id = p.type " + + "LEFT JOIN vendors_list v ON p.vendor_name REGEXP '^[0-9]+$' AND v.id = p.vendor_name " + + "WHERE p.is_active = 1 AND p.is_delete = 0"); + List params = new ArrayList<>(); + + if (type != null && !type.trim().isEmpty()) { + String category = type.trim().toLowerCase(); + if (category.equals("asd")) { + sql.append(" AND (LOWER(p.type) = 'asd' OR LOWER(p.type) LIKE '%asd%' OR LOWER(t.type_name) LIKE '%asd%' OR LOWER(t.type_name) LIKE '%additional security%')"); + } else if (category.equals("agreement")) { + sql.append(" AND (LOWER(p.type) LIKE '%agreement%' OR LOWER(t.type_name) LIKE '%agreement%')"); + } else if (category.equals("sd")) { + sql.append(" AND ((LOWER(p.type) = 'sd' OR LOWER(p.type) LIKE '%security%' OR LOWER(t.type_name) LIKE '%security%') " + + "AND LOWER(p.type) NOT LIKE '%additional security%' AND LOWER(p.type) NOT LIKE '%asd%' " + + "AND (t.type_name IS NULL OR (LOWER(t.type_name) NOT LIKE '%additional security%' AND LOWER(t.type_name) NOT LIKE '%asd%')))"); + } else if (category.equals("tax invoice")) { + sql.append(" AND (LOWER(p.type) LIKE '%invoice%' OR LOWER(p.type) LIKE '%bill%' OR LOWER(t.type_name) LIKE '%invoice%' OR LOWER(t.type_name) LIKE '%bill%')"); + } else if (category.equals("emd")) { + sql.append(" AND (LOWER(p.type) = 'emd' OR LOWER(p.type) LIKE '%earnest%' OR LOWER(t.type_name) LIKE '%emd%' OR LOWER(t.type_name) LIKE '%earnest%')"); + } else if (category.equals("bank guarantee")) { + sql.append(" AND (LOWER(p.type) LIKE '%guarantee%' OR LOWER(p.type) = 'bg' OR LOWER(t.type_name) LIKE '%guarantee%' OR LOWER(t.type_name) = 'bg')"); + } else if (category.equals("delivery chellan")) { + sql.append(" AND (LOWER(p.type) LIKE '%chellan%' OR LOWER(p.type) LIKE '%challan%' OR LOWER(p.type) = 'dc' " + + "OR LOWER(t.type_name) LIKE '%chellan%' OR LOWER(t.type_name) LIKE '%challan%' OR LOWER(t.type_name) = 'dc')"); + } else { + sql.append(" AND (LOWER(p.type) = ? OR LOWER(t.type_name) = ?)"); + params.add(category); + params.add(category); + } + } + + if (fromDate != null && !fromDate.trim().isEmpty()) { + sql.append(" AND p.received_date >= ?"); + params.add(parseDate(fromDate)); + } + + if (toDate != null && !toDate.trim().isEmpty()) { + sql.append(" AND p.received_date <= ?"); + params.add(parseDate(toDate)); + } + + if (status != null && !status.trim().isEmpty()) { + sql.append(" AND LOWER(p.status) = ?"); + params.add(status.trim().toLowerCase()); + } + + sql.append(" ORDER BY p.order_by ASC, p.received_date DESC, p.id DESC"); + + try { + return jdbcTemplate.queryForList(sql.toString(), params.toArray()); + } catch (Exception e) { + System.err.println("Error searching payment tracking details: " + e.getMessage()); + return new ArrayList<>(); + } + } + + public Map getDetailById(int id) { + String sql = "SELECT * FROM payment_tracking_details WHERE id = ? AND is_active = 1 AND is_delete = 0"; + try { + List> list = jdbcTemplate.queryForList(sql, id); + if (list != null && !list.isEmpty()) { + return list.get(0); + } + } catch (Exception e) { + System.err.println("Error fetching payment tracking detail ID " + id + ": " + e.getMessage()); + } + return null; + } + + public boolean saveOrUpdateDetail(Map payload) { + Object idObj = payload.get("id"); + java.sql.Date receivedDate = parseDate(payload.get("received_date")); + String vendorName = (String) payload.get("vendor_name"); + String subject = (String) payload.get("subject"); + String amount = (String) payload.get("amount"); + String invoiceNo = (String) payload.get("invoice_no"); + String receiptNo = payload.get("receiptno") != null ? String.valueOf(payload.get("receiptno")) : null; + java.sql.Date invoiceDate = parseDate(payload.get("invoice_date")); + String type = (String) payload.get("type"); + String physicalFileNo = (String) payload.get("physical_file_no"); + String remarks = (String) payload.get("remarks"); + String tat = (String) payload.get("tat"); + String status = (String) payload.get("status"); + String followup = (String) payload.get("followup"); + String myfollowup = (String) payload.get("myfollowup"); + String orderBy = (String) payload.get("order_by"); + String filePath = (String) payload.get("file_path"); + + if (idObj != null && !String.valueOf(idObj).trim().isEmpty()) { + // Update + int id = Integer.parseInt(String.valueOf(idObj).trim()); + String sql = "UPDATE payment_tracking_details SET " + + "received_date = ?, vendor_name = ?, subject = ?, amount = ?, invoice_no = ?, " + + "receiptno = ?, invoice_date = ?, type = ?, physical_file_no = ?, remarks = ?, " + + "tat = ?, status = ?, followup = ?, myfollowup = ?, order_by = ?, file_path = ? " + + "WHERE id = ? AND is_active = 1 AND is_delete = 0"; + try { + int rows = jdbcTemplate.update(sql, receivedDate, vendorName, subject, amount, invoiceNo, + receiptNo, invoiceDate, type, physicalFileNo, remarks, + tat, status, followup, myfollowup, orderBy, filePath, id); + return rows > 0; + } catch (Exception e) { + System.err.println("Error updating payment tracking detail ID " + id + ": " + e.getMessage()); + return false; + } + } else { + // Insert + String sql = "INSERT INTO payment_tracking_details (" + + "received_date, vendor_name, subject, amount, invoice_no, receiptno, " + + "invoice_date, type, physical_file_no, remarks, tat, status, " + + "followup, myfollowup, is_active, is_delete, order_by, file_path" + + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, 0, ?, ?)"; + try { + int rows = jdbcTemplate.update(sql, receivedDate, vendorName, subject, amount, invoiceNo, + receiptNo, invoiceDate, type, physicalFileNo, remarks, + tat, status, followup, myfollowup, orderBy, filePath); + return rows > 0; + } catch (Exception e) { + System.err.println("Error saving payment tracking detail: " + e.getMessage()); + return false; + } + } + } + + public boolean deleteDetail(int id) { + String sql = "UPDATE payment_tracking_details SET is_active = 0, is_delete = 1 WHERE id = ?"; + try { + int rows = jdbcTemplate.update(sql, id); + return rows > 0; + } catch (Exception e) { + System.err.println("Error soft-deleting payment tracking detail ID " + id + ": " + e.getMessage()); + return false; + } + } + + private java.sql.Date parseDate(Object obj) { + if (obj == null || String.valueOf(obj).trim().isEmpty()) { + return null; + } + String str = String.valueOf(obj).trim(); + try { + // Support both yyyy-MM-dd and dd/MM/yyyy + if (str.contains("/")) { + String[] parts = str.split("/"); + if (parts.length == 3) { + // Convert dd/MM/yyyy to yyyy-MM-dd + str = parts[2] + "-" + parts[1] + "-" + parts[0]; + } + } + return java.sql.Date.valueOf(str); + } catch (Exception e) { + System.err.println("Error parsing date '" + obj + "': " + e.getMessage()); + return null; + } + } + + private java.sql.Timestamp parseTimestamp(Object obj) { + if (obj == null || String.valueOf(obj).trim().isEmpty()) { + return null; + } + String str = String.valueOf(obj).trim(); + try { + if (str.contains("/")) { + // Parse format dd/MM/yyyy HH:mm:ss or similar if provided + // For simplicity, fallback to current time or standard parsing if it fails + } + if (str.contains("T")) { + str = str.replace("T", " "); + } + if (str.length() == 16) { + str = str + ":00"; + } + return java.sql.Timestamp.valueOf(str); + } catch (Exception e) { + // Try parsing as DATE first, then convert to TIMESTAMP + java.sql.Date d = parseDate(obj); + if (d != null) { + return new java.sql.Timestamp(d.getTime()); + } + System.err.println("Error parsing timestamp '" + obj + "': " + e.getMessage()); + return null; + } + } + + public List> getActiveTypes() { + String sql = "SELECT id, type_name FROM type_list " + + "WHERE is_active = 1 AND is_delete = 0 " + + "ORDER BY order_by ASC, type_name ASC"; + try { + return jdbcTemplate.queryForList(sql); + } catch (Exception e) { + System.err.println("Error fetching active types: " + e.getMessage()); + return new ArrayList<>(); + } + } + + public List> getActiveVendors() { + String sql = "SELECT id, vendor_name FROM vendors_list " + + "WHERE is_active = 1 AND is_delete = 0 " + + "ORDER BY order_by ASC, vendor_name ASC"; + try { + return jdbcTemplate.queryForList(sql); + } catch (Exception e) { + System.err.println("Error fetching active vendors: " + e.getMessage()); + return new ArrayList<>(); + } + } +} diff --git a/src/main/resources/application-local.properties b/src/main/resources/application-local.properties index 1544b26..0709075 100644 --- a/src/main/resources/application-local.properties +++ b/src/main/resources/application-local.properties @@ -7,7 +7,7 @@ server.port=8084 # =============================== # MySQL Database Configuration # =============================== -# Local DB server +# Local DB server spring.datasource.url=jdbc:mysql://localhost:3306/gcc_manpower spring.datasource.username=root spring.datasource.password=root @@ -31,7 +31,7 @@ logging.level.org.hibernate.SQL=DEBUG logging.level.org.hibernate.type.descriptor.sql=TRACE # Production context path -server.servlet.context-path=/ +server.servlet.context-path=/gcc_manpower # Disable Thymeleaf caching for hot-swapping templates spring.thymeleaf.cache=false diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index edf4c9a..7197b79 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,5 +1,5 @@ -#spring.profiles.active=local -spring.profiles.active=prod +spring.profiles.active=local +#spring.profiles.active=prod spring.application.name=gcc-manpower server.servlet.session.timeout=10m - \ No newline at end of file + \ No newline at end of file diff --git a/src/main/resources/templates/fragments/navbar.html b/src/main/resources/templates/fragments/navbar.html index 83bfd10..33b8bcf 100644 --- a/src/main/resources/templates/fragments/navbar.html +++ b/src/main/resources/templates/fragments/navbar.html @@ -16,6 +16,10 @@ class=" fa-solid fa-house"> Home +