Browse Source

newly added controller , service , pages and changes in tapal , toner, adjustment management projects

master
yoganandhank 2 months ago
parent
commit
a7c1f69298
  1. 9
      src/main/java/com/gcc_manpower/config/WebConfig.java
  2. 71
      src/main/java/com/gcc_manpower/gccservicepaymenttracker/controller/GccServicePaymentTrackerController.java
  3. 26
      src/main/java/com/gcc_manpower/gccservicepaymenttracker/service/GccServicePaymentTrackerService.java
  4. 287
      src/main/java/com/gcc_manpower/gcctapaldetailsmanagement/controller/TapalController.java
  5. 383
      src/main/java/com/gcc_manpower/gcctapaldetailsmanagement/service/TapalService.java
  6. 12
      src/main/java/com/gcc_manpower/gcctonermanagement/controller/TonerController.java
  7. 95
      src/main/java/com/gcc_manpower/gcctonermanagement/service/TonerService.java
  8. 185
      src/main/resources/templates/gccadjustmentmanagement/details.html
  9. 142
      src/main/resources/templates/gccservicepaymenttracker/dashboard.html
  10. 112
      src/main/resources/templates/gccservicepaymenttracker/details.html
  11. 4883
      src/main/resources/templates/gcctapaldetailsmanagement/dashboard.html
  12. 1962
      src/main/resources/templates/gcctapaldetailsmanagement/details.html
  13. 2
      src/main/resources/templates/gcctapaldetailsmanagement/login.html
  14. 2477
      src/main/resources/templates/gcctonermanagement/upload.html

9
src/main/java/com/gcc_manpower/config/WebConfig.java

@ -24,6 +24,9 @@ public class WebConfig implements WebMvcConfigurer {
@Value("${adjustment.upload.path:uploads/file-data}")
private String adjustmentUploadPathConfig;
@Value("${tapal.upload.path:gcctapalfiles}")
private String tapalUploadPathConfig;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// Resolve absolute path (supports both relative and absolute paths)
@ -59,6 +62,12 @@ public class WebConfig implements WebMvcConfigurer {
registry.addResourceHandler("/gccadjustmentmanagementfiles/**")
.addResourceLocations(adjustmentUploadPath);
// Map URL path /gcctapalfiles/** to the configured tapal folder path
String tapalUploadPath = Paths.get(tapalUploadPathConfig).toAbsolutePath().toUri()
.toString();
registry.addResourceHandler("/gcctapalfiles/**")
.addResourceLocations(tapalUploadPath);
// Map URL path /uploads/** to the physical uploads folder in the project root
String rootUploadPath = Paths.get("uploads").toAbsolutePath().toUri().toString();
registry.addResourceHandler("/uploads/**")

71
src/main/java/com/gcc_manpower/gccservicepaymenttracker/controller/GccServicePaymentTrackerController.java

@ -93,12 +93,13 @@ public class GccServicePaymentTrackerController {
Map<String, Object> response = new HashMap<>();
try {
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(usrName, usrPass);
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(usrName,
usrPass);
Authentication authentication = authenticationManager.authenticate(authenticationToken);
SecurityContextHolder.getContext().setAuthentication(authentication);
session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());
session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY,
SecurityContextHolder.getContext());
String role = authentication.getAuthorities().stream()
.map(auth -> auth.getAuthority().replace("ROLE_", ""))
@ -309,6 +310,70 @@ public class GccServicePaymentTrackerController {
return response;
}
@PostMapping("/api/upload-screenshot")
@ResponseBody
public Map<String, Object> uploadScreenshot(
@RequestParam("file") MultipartFile file,
HttpSession session) {
Map<String, Object> response = new HashMap<>();
String username = (String) session.getAttribute("pay_usrName");
if (username == null) {
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("pay_usrRole");
if (usrRole == null) {
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 parentDir = new File(paymentTrackerUploadPathConfig).getAbsoluteFile();
File screenshotDir = new File(parentDir, "screenshots");
if (!screenshotDir.exists()) {
screenshotDir.mkdirs();
}
String originalFilename = file.getOriginalFilename();
String nameWithoutExt = "screenshot";
String ext = ".png";
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(screenshotDir, savedFilename).getAbsoluteFile();
file.transferTo(destFile);
String fileWebUrl = "/gccpaymenttrackerfiles/screenshots/" + savedFilename;
response.put("success", true);
response.put("filePath", fileWebUrl);
} catch (Exception e) {
response.put("success", false);
response.put("error", "Screenshot upload failed: " + e.getMessage());
}
return response;
}
@GetMapping("/api/types")
@ResponseBody
public List<Map<String, Object>> getActiveTypes() {

26
src/main/java/com/gcc_manpower/gccservicepaymenttracker/service/GccServicePaymentTrackerService.java

@ -235,6 +235,7 @@ public class GccServicePaymentTrackerService {
String orderBy = (String) payload.get("order_by");
String filePath = (String) payload.get("file_path");
String paymentReview = (String) payload.get("payment_review");
String emailpath = (String) payload.get("mail_screenshot_path");
if (idObj != null && !String.valueOf(idObj).trim().isEmpty()) {
// Update
@ -246,9 +247,9 @@ public class GccServicePaymentTrackerService {
if (old != null) {
String insertHistorySql = "INSERT INTO payment_tracking_details_history ("
+ "detail_id, received_date, vendor_name, subject, amount, invoice_no, receiptno, "
+ "invoice_date, type, physical_file_no, remarks, tat, status, followup, myfollowup, "
+ "invoice_date, type, physical_file_no, remarks, mail_screenshot_path,tat, status, followup, myfollowup, "
+ "is_active, is_delete, order_by, file_path, payment_review, cdate, updated_at, updated_by"
+ ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+ ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ,?)";
jdbcTemplate.update(insertHistorySql,
old.get("id"),
old.get("received_date"),
@ -261,6 +262,7 @@ public class GccServicePaymentTrackerService {
old.get("type"),
old.get("physical_file_no"),
old.get("remarks"),
old.get("mail_screenshot_path"),
old.get("tat"),
old.get("status"),
old.get("followup"),
@ -280,13 +282,13 @@ public class GccServicePaymentTrackerService {
String sql = "UPDATE payment_tracking_details SET "
+ "received_date = ?, vendor_name = ?, subject = ?, amount = ?, invoice_no = ?, "
+ "receiptno = ?, invoice_date = ?, type = ?, physical_file_no = ?, remarks = ?, "
+ "receiptno = ?, invoice_date = ?, type = ?, physical_file_no = ?, remarks = ?, mail_screenshot_path = ?, "
+ "tat = ?, status = ?, followup = ?, myfollowup = ?, order_by = ?, file_path = ?, "
+ "payment_review = ?, updated_by = ?, updated_date = ? "
+ "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,
receiptNo, invoiceDate, type, physicalFileNo, remarks, emailpath,
tat, status, followup, myfollowup, orderBy, filePath,
paymentReview, userId, new java.sql.Timestamp(System.currentTimeMillis()), id);
return rows > 0;
@ -298,14 +300,14 @@ public class GccServicePaymentTrackerService {
// 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, "
+ "invoice_date, type, physical_file_no, remarks, mail_screenshot_path, tat, status, "
+ "followup, myfollowup, is_active, is_delete, order_by, file_path, "
+ "payment_review, updated_by, updated_date, cdate"
+ ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, 0, ?, ?, ?, ?, ?, ?)";
+ ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, 0, ?, ?, ?, ?, ?, ?)";
try {
java.sql.Timestamp now = new java.sql.Timestamp(System.currentTimeMillis());
int rows = jdbcTemplate.update(sql, receivedDate, vendorName, subject, amount, invoiceNo,
receiptNo, invoiceDate, type, physicalFileNo, remarks,
receiptNo, invoiceDate, type, physicalFileNo, remarks, emailpath,
tat, status, followup, myfollowup, orderBy, filePath,
paymentReview, userId, now, now);
return rows > 0;
@ -334,9 +336,9 @@ public class GccServicePaymentTrackerService {
try {
String histSql = "INSERT INTO payment_tracking_details_history ("
+ "detail_id, received_date, vendor_name, subject, amount, invoice_no, receiptno, "
+ "invoice_date, type, physical_file_no, remarks, tat, status, followup, myfollowup, "
+ "invoice_date, type, physical_file_no, remarks, mail_screenshot_path, tat, status, followup, myfollowup, "
+ "is_active, is_delete, order_by, file_path, payment_review, cdate, updated_at, updated_by"
+ ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+ ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
jdbcTemplate.update(histSql,
id,
old.get("received_date"),
@ -349,6 +351,7 @@ public class GccServicePaymentTrackerService {
old.get("type"),
old.get("physical_file_no"),
remarks,
old.get("mail_screenshot_path"),
old.get("tat"),
old.get("status"),
old.get("followup"),
@ -489,9 +492,9 @@ public class GccServicePaymentTrackerService {
try {
String histSql = "INSERT INTO payment_tracking_details_history ("
+ "detail_id, received_date, vendor_name, subject, amount, invoice_no, receiptno, "
+ "invoice_date, type, physical_file_no, remarks, tat, status, followup, myfollowup, "
+ "invoice_date, type, physical_file_no, remarks, mail_screenshot_path, tat, status, followup, myfollowup, "
+ "is_active, is_delete, order_by, file_path, payment_review, cdate, updated_at, updated_by"
+ ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+ ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
jdbcTemplate.update(histSql,
id,
old.get("received_date"),
@ -504,6 +507,7 @@ public class GccServicePaymentTrackerService {
old.get("type"),
old.get("physical_file_no"),
"Record restored", // remarks
old.get("mail_screenshot_path"),
old.get("tat"),
old.get("status"),
old.get("followup"),

287
src/main/java/com/gcc_manpower/gcctapaldetailsmanagement/controller/TapalController.java

@ -1,9 +1,14 @@
package com.gcc_manpower.gcctapaldetailsmanagement.controller;
import java.io.File;
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.http.CacheControl;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
@ -14,9 +19,11 @@ 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.RequestBody;
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.gcctapaldetailsmanagement.service.TapalService;
@ -33,6 +40,9 @@ public class TapalController {
@Autowired
private AuthenticationManager authenticationManager;
@Value("${tapal.upload.path:gcctapalfiles}")
private String tapalUploadPathConfig;
@GetMapping({ "", "/", "/dashboard" })
public String viewDashboard(Model model, HttpSession session) {
String username = (String) session.getAttribute("tap_usrName");
@ -51,6 +61,23 @@ public class TapalController {
return "gcctapaldetailsmanagement/dashboard";
}
@GetMapping("/details")
public String viewDetails(HttpSession session, Model model) {
String username = (String) session.getAttribute("tap_usrName");
if (username == null) {
return "redirect:/gcctapaldetailsmanagement/login";
}
String usrRole = (String) session.getAttribute("tap_usrRole");
boolean isAdmin = "ADMIN".equalsIgnoreCase(usrRole);
model.addAttribute("isLoggedIn", true);
model.addAttribute("isAdmin", isAdmin);
model.addAttribute("usrName", username);
model.addAttribute("curPage", "gcctapaldetailsmanagement");
return "gcctapaldetailsmanagement/details";
}
@GetMapping("/login")
public String login(HttpSession session) {
return "gcctapaldetailsmanagement/login";
@ -103,4 +130,264 @@ public class TapalController {
request.getSession(true);
return "redirect:/gcctapaldetailsmanagement/login";
}
@GetMapping("/api/counts")
@ResponseBody
public ResponseEntity<Map<String, Integer>> getCounts() {
return ResponseEntity.ok()
.cacheControl(CacheControl.noCache().mustRevalidate())
.body(tapalService.getCountsByCategory());
}
@GetMapping("/api/list")
@ResponseBody
public ResponseEntity<List<Map<String, Object>>> 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<Map<String, Object>> details = tapalService.searchTapals(category, fromDate, toDate, status);
return ResponseEntity.ok()
.cacheControl(CacheControl.noCache().mustRevalidate())
.body(details);
}
@PostMapping("/api/save")
@ResponseBody
public Map<String, Object> saveDetail(
@RequestBody Map<String, Object> payload,
HttpSession session) {
Map<String, Object> response = new HashMap<>();
String username = (String) session.getAttribute("tap_usrName");
if (username == null) {
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("tap_usrRole");
if (usrRole == null) {
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 = tapalService.saveOrUpdateTapal(payload, username);
response.put("success", saved);
if (!saved) {
response.put("error", "Failed to save Tapal details to database.");
}
} catch (Exception e) {
response.put("success", false);
response.put("error", "Error: " + e.getMessage());
}
return response;
}
@PostMapping("/api/delete")
@ResponseBody
public Map<String, Object> deleteDetail(
@RequestParam("id") int id,
@RequestParam(value = "remarks", required = false, defaultValue = "") String remarks,
HttpSession session) {
Map<String, Object> response = new HashMap<>();
String username = (String) session.getAttribute("tap_usrName");
if (username == null) {
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("tap_usrRole");
if (usrRole == null) {
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 = tapalService.deleteTapal(id, remarks, username);
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-file")
@ResponseBody
public Map<String, Object> uploadFile(
@RequestParam("file") MultipartFile file,
@RequestParam(value = "type", required = false, defaultValue = "tapal") String type,
HttpSession session) {
Map<String, Object> response = new HashMap<>();
String username = (String) session.getAttribute("tap_usrName");
if (username == null) {
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("tap_usrRole");
if (usrRole == null) {
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 parentDir = new File(tapalUploadPathConfig).getAbsoluteFile();
File destDir = parentDir;
String webPathPrefix = "/gcctapalfiles/";
if ("oc".equalsIgnoreCase(type)) {
destDir = new File(parentDir, "oc");
webPathPrefix = "/gcctapalfiles/oc/";
}
if (!destDir.exists()) {
destDir.mkdirs();
}
String originalFilename = file.getOriginalFilename();
String nameWithoutExt = type;
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(destDir, savedFilename).getAbsoluteFile();
file.transferTo(destFile);
String fileWebUrl = webPathPrefix + 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/categories")
@ResponseBody
public List<Map<String, Object>> getActiveCategories() {
return tapalService.getActiveCategories();
}
@GetMapping("/api/statuslist")
@ResponseBody
public List<Map<String, Object>> getStatusList() {
return tapalService.getActiveStatuses();
}
@GetMapping("/api/history")
@ResponseBody
public ResponseEntity<List<Map<String, Object>>> getHistory(
@RequestParam("tapalNo") String tapalNo,
HttpSession session) {
String username = (String) session.getAttribute("tap_usrName");
if (username == null) {
username = (String) session.getAttribute("usrName");
}
if (username == null) {
return ResponseEntity.status(401).body(null);
}
return ResponseEntity.ok()
.cacheControl(CacheControl.noCache().mustRevalidate())
.body(tapalService.getHistory(tapalNo));
}
@GetMapping("/api/deleted-list")
@ResponseBody
public ResponseEntity<List<Map<String, Object>>> getDeletedList(HttpSession session) {
String username = (String) session.getAttribute("tap_usrName");
if (username == null) {
username = (String) session.getAttribute("usrName");
}
if (username == null) {
return ResponseEntity.status(401).body(null);
}
return ResponseEntity.ok()
.cacheControl(CacheControl.noCache().mustRevalidate())
.body(tapalService.getDeletedTapals());
}
@PostMapping("/api/restore")
@ResponseBody
public Map<String, Object> restoreDetail(
@RequestParam("id") int id,
HttpSession session) {
Map<String, Object> response = new HashMap<>();
String username = (String) session.getAttribute("tap_usrName");
if (username == null) {
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("tap_usrRole");
if (usrRole == null) {
usrRole = (String) session.getAttribute("usrRole");
}
if (!"ADMIN".equalsIgnoreCase(usrRole)) {
response.put("success", false);
response.put("error", "Access denied! Only admins can restore records.");
return response;
}
try {
boolean restored = tapalService.restoreTapal(id, username);
response.put("success", restored);
if (!restored) {
response.put("error", "Failed to restore record.");
}
} catch (Exception e) {
response.put("success", false);
response.put("error", "Error: " + e.getMessage());
}
return response;
}
}

383
src/main/java/com/gcc_manpower/gcctapaldetailsmanagement/service/TapalService.java

@ -1,6 +1,8 @@
package com.gcc_manpower.gcctapaldetailsmanagement.service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -21,14 +23,385 @@ public class TapalService {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public List<Map<String, Object>> getAllTapalsStatus() {
String sql = "select * from tapal_status_list where is_active = 1 and is_delete=0";
public List<Map<String, Object>> getActiveCategories() {
String sql = "SELECT id, category_name FROM tapal_category_list "
+ "WHERE is_active = 1 AND is_delete = 0 "
+ "ORDER BY order_by ASC, category_name ASC";
try {
return this.jdbcTemplate.queryForList(sql);
return jdbcTemplate.queryForList(sql);
} catch (Exception e) {
System.out.println(e.getMessage());
return Collections.emptyList();
System.err.println("Error fetching active categories: " + e.getMessage());
return new ArrayList<>();
}
}
public List<Map<String, Object>> getActiveStatuses() {
String sql = "SELECT id, status_name FROM tapal_status_list "
+ "WHERE is_active = 1 AND is_delete = 0 "
+ "ORDER BY order_by ASC, status_name ASC";
try {
return jdbcTemplate.queryForList(sql);
} catch (Exception e) {
System.err.println("Error fetching active statuses: " + e.getMessage());
return new ArrayList<>();
}
}
public Map<String, Integer> getCountsByCategory() {
Map<String, Integer> counts = new HashMap<>();
List<Map<String, Object>> categories = getActiveCategories();
for (Map<String, Object> cat : categories) {
String catName = String.valueOf(cat.get("category_name")).toLowerCase().trim();
counts.put(catName, 0);
}
counts.put("total", 0);
counts.put("status_not_updated", 0);
counts.put("completed", 0);
counts.put("pending", 0);
counts.put("age_1_15", 0);
counts.put("age_16_30", 0);
counts.put("age_31_60", 0);
counts.put("age_61_90", 0);
counts.put("age_91_120", 0);
counts.put("age_over_120", 0);
try {
String sqlTotal = "SELECT COUNT(*) FROM tapal_tracking_details WHERE is_active = 1 AND is_delete = 0";
Integer totalCount = jdbcTemplate.queryForObject(sqlTotal, Integer.class);
counts.put("total", totalCount != null ? totalCount : 0);
String sqlMissingCat = "SELECT COUNT(*) FROM tapal_tracking_details WHERE is_active = 1 AND is_delete = 0 AND (cat_type_id IS NULL OR TRIM(cat_type_id) = '')";
Integer missingCatCount = jdbcTemplate.queryForObject(sqlMissingCat, Integer.class);
counts.put("status_not_updated", missingCatCount != null ? missingCatCount : 0);
String sql = "SELECT "
+ "CASE WHEN t.cat_type_id REGEXP '^[0-9]+$' THEN c.category_name ELSE t.cat_type_id END as category_resolved, "
+ "COUNT(*) as cnt "
+ "FROM tapal_tracking_details t "
+ "LEFT JOIN tapal_category_list c ON t.cat_type_id REGEXP '^[0-9]+$' AND c.id = CAST(t.cat_type_id AS UNSIGNED) "
+ "WHERE t.is_active = 1 AND t.is_delete = 0 "
+ "GROUP BY category_resolved";
List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql);
for (Map<String, Object> row : rows) {
String catName = String.valueOf(row.get("category_resolved")).toLowerCase().trim();
Number countNum = (Number) row.get("cnt");
int count = countNum != null ? countNum.intValue() : 0;
counts.put(catName, counts.getOrDefault(catName, 0) + count);
}
// Calculate completed, pending, and age counts
String sqlAll = "SELECT tapal_received_date, remarks FROM tapal_tracking_details WHERE is_active = 1 AND is_delete = 0";
List<Map<String, Object>> records = jdbcTemplate.queryForList(sqlAll);
int completed = 0;
int pending = 0;
int age_1_15 = 0;
int age_16_30 = 0;
int age_31_60 = 0;
int age_61_90 = 0;
int age_91_120 = 0;
int age_over_120 = 0;
for (Map<String, Object> r : records) {
String remarks = (String) r.get("remarks");
java.sql.Date receivedDate = (java.sql.Date) r.get("tapal_received_date");
boolean isPending = (remarks == null || remarks.trim().isEmpty() || remarks.trim().equals("-"));
if (isPending) {
pending++;
int age = 0;
if (receivedDate != null) {
long diffTime = Math.abs(System.currentTimeMillis() - receivedDate.getTime());
age = (int) Math.ceil(diffTime / (1000.0 * 60.0 * 60.0 * 24.0)) - 1;
}
if (age >= 0 && age <= 15) {
age_1_15++;
} else if (age >= 16 && age <= 30) {
age_16_30++;
} else if (age >= 31 && age <= 60) {
age_31_60++;
} else if (age >= 61 && age <= 90) {
age_61_90++;
} else if (age >= 91 && age <= 120) {
age_91_120++;
} else if (age > 120) {
age_over_120++;
}
} else {
completed++;
}
}
counts.put("completed", completed);
counts.put("pending", pending);
counts.put("age_1_15", age_1_15);
counts.put("age_16_30", age_16_30);
counts.put("age_31_60", age_31_60);
counts.put("age_61_90", age_61_90);
counts.put("age_91_120", age_91_120);
counts.put("age_over_120", age_over_120);
} catch (Exception e) {
System.err.println("Error getting Tapal counts: " + e.getMessage());
}
return counts;
}
public List<Map<String, Object>> searchTapals(String category, String fromDate, String toDate, String status) {
StringBuilder sql = new StringBuilder(
"SELECT t.*, "
+ "c.category_name as resolved_category, "
+ "s.status_name as resolved_status, "
+ "u.usr_name as updated_by_name "
+ "FROM tapal_tracking_details t "
+ "LEFT JOIN tapal_category_list c ON TRIM(t.cat_type_id) REGEXP '^[0-9]+$' AND c.id = CAST(TRIM(t.cat_type_id) AS UNSIGNED) "
+ "LEFT JOIN tapal_status_list s ON TRIM(t.status_id) REGEXP '^[0-9]+$' AND s.id = CAST(TRIM(t.status_id) AS UNSIGNED) "
+ "LEFT JOIN app_user u ON (t.updated_by = CAST(u.usr_id AS CHAR) OR t.updated_by = u.usr_name) "
+ "WHERE t.is_active = 1 AND t.is_delete = 0");
List<Object> params = new ArrayList<>();
if (category != null && !category.trim().isEmpty()) {
String categoryName = category.trim().toLowerCase();
if (categoryName.equals("status_not_updated")) {
sql.append(" AND (t.cat_type_id IS NULL OR TRIM(t.cat_type_id) = '')");
} else {
sql.append(" AND (LOWER(t.cat_type_id) = ? OR LOWER(c.category_name) = ?)");
params.add(categoryName);
params.add(categoryName);
}
}
if (fromDate != null && !fromDate.trim().isEmpty()) {
sql.append(" AND t.tapal_received_date >= ?");
params.add(parseDate(fromDate));
}
if (toDate != null && !toDate.trim().isEmpty()) {
sql.append(" AND t.tapal_received_date <= ?");
params.add(parseDate(toDate));
}
if (status != null && !status.trim().isEmpty()) {
if (status.trim().matches("^[0-9]+$")) {
sql.append(
" AND (t.status_id = ? OR (NOT t.status_id REGEXP '^[0-9]+$' AND t.status_id = (SELECT status_name FROM tapal_status_list WHERE id = ? LIMIT 1)))");
params.add(status.trim());
params.add(status.trim());
} else {
sql.append(
" AND (LOWER(t.status_id) = ? OR (t.status_id REGEXP '^[0-9]+$' AND LOWER(s.status_name) = ?))");
params.add(status.trim().toLowerCase());
params.add(status.trim().toLowerCase());
}
}
sql.append(" ORDER BY t.tapal_received_date DESC, t.id DESC");
try {
return jdbcTemplate.queryForList(sql.toString(), params.toArray());
} catch (Exception e) {
System.err.println("Error searching Tapal details: " + e.getMessage());
return new ArrayList<>();
}
}
public Map<String, Object> getTapalById(int id) {
String sql = "SELECT * FROM tapal_tracking_details WHERE id = ? AND is_active = 1 AND is_delete = 0";
try {
List<Map<String, Object>> list = jdbcTemplate.queryForList(sql, id);
if (list != null && !list.isEmpty()) {
return list.get(0);
}
} catch (Exception e) {
System.err.println("Error fetching Tapal detail ID " + id + ": " + e.getMessage());
}
return null;
}
private void saveToHistory(Map<String, Object> old, String updatedBy) {
String sql = "INSERT INTO tapal_tracking_details_history ("
+ "tapal_no, tapal_received_date, request_from, subject, cat_type_id, status_id, "
+ "remarks, tapal_file_path, oc_file_path, cdate, updated_date, updated_by, "
+ "is_active, is_delete"
+ ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
try {
jdbcTemplate.update(sql,
old.get("tapal_no"),
old.get("tapal_received_date"),
old.get("request_from"),
old.get("subject"),
old.get("cat_type_id"),
old.get("status_id"),
old.get("remarks"),
old.get("tapal_file_path"),
old.get("oc_file_path"),
old.get("cdate"),
new java.sql.Timestamp(System.currentTimeMillis()),
updatedBy,
old.get("is_active"),
old.get("is_delete"));
} catch (Exception e) {
System.err.println("Error inserting Tapal history: " + e.getMessage());
}
}
public boolean saveOrUpdateTapal(Map<String, Object> payload, String updatedBy) {
Object idObj = payload.get("id");
String tapalNo = (String) payload.get("tapal_no");
java.sql.Date tapalReceivedDate = parseDate(payload.get("tapal_received_date"));
String requestFrom = (String) payload.get("request_from");
String subject = (String) payload.get("subject");
String catTypeId = (String) payload.get("cat_type_id");
String statusId = (String) payload.get("status_id");
String remarks = (String) payload.get("remarks");
String tapalFilePath = (String) payload.get("tapal_file_path");
String ocFilePath = (String) payload.get("oc_file_path");
if (idObj != null && !String.valueOf(idObj).trim().isEmpty()) {
int id = Integer.parseInt(String.valueOf(idObj).trim());
Map<String, Object> old = getTapalById(id);
if (old != null) {
saveToHistory(old, updatedBy);
}
String sql = "UPDATE tapal_tracking_details SET "
+ "tapal_no = ?, tapal_received_date = ?, request_from = ?, subject = ?, "
+ "cat_type_id = ?, status_id = ?, remarks = ?, tapal_file_path = ?, oc_file_path = ?, "
+ "updated_date = ?, updated_by = ? "
+ "WHERE id = ? AND is_active = 1 AND is_delete = 0";
try {
int rows = jdbcTemplate.update(sql, tapalNo, tapalReceivedDate, requestFrom, subject,
catTypeId, statusId, remarks, tapalFilePath, ocFilePath,
new java.sql.Timestamp(System.currentTimeMillis()), updatedBy, id);
return rows > 0;
} catch (Exception e) {
System.err.println("Error updating Tapal detail ID " + id + ": " + e.getMessage());
return false;
}
} else {
String sql = "INSERT INTO tapal_tracking_details ("
+ "tapal_no, tapal_received_date, request_from, subject, cat_type_id, status_id, "
+ "remarks, tapal_file_path, oc_file_path, updated_by, updated_date, cdate, "
+ "is_active, is_delete"
+ ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, 0)";
try {
java.sql.Timestamp now = new java.sql.Timestamp(System.currentTimeMillis());
int rows = jdbcTemplate.update(sql, tapalNo, tapalReceivedDate, requestFrom, subject,
catTypeId, statusId, remarks, tapalFilePath, ocFilePath, updatedBy, now, now);
return rows > 0;
} catch (Exception e) {
System.err.println("Error inserting Tapal details: " + e.getMessage());
return false;
}
}
}
public boolean deleteTapal(int id, String remarks, String updatedBy) {
String sql = "UPDATE tapal_tracking_details SET is_active = 0, is_delete = 1, remarks = ?, updated_by = ?, updated_date = ? WHERE id = ?";
try {
Map<String, Object> old = null;
try {
old = jdbcTemplate.queryForMap("SELECT * FROM tapal_tracking_details WHERE id = ?", id);
} catch (Exception e) {
System.err.println("Could not find old record for history before delete: " + e.getMessage());
}
int rows = jdbcTemplate.update(sql, remarks, updatedBy, new java.sql.Timestamp(System.currentTimeMillis()),
id);
if (rows > 0 && old != null) {
old.put("remarks", remarks);
old.put("is_active", 0);
old.put("is_delete", 1);
saveToHistory(old, updatedBy);
}
return rows > 0;
} catch (Exception e) {
System.err.println("Error soft-deleting Tapal detail ID " + id + ": " + e.getMessage());
return false;
}
}
public boolean restoreTapal(int id, String updatedBy) {
String sql = "UPDATE tapal_tracking_details SET is_active = 1, is_delete = 0, remarks = 'Record restored', updated_by = ?, updated_date = ? WHERE id = ?";
try {
Map<String, Object> old = null;
try {
old = jdbcTemplate.queryForMap("SELECT * FROM tapal_tracking_details WHERE id = ?", id);
} catch (Exception e) {
System.err.println("Could not find old record for history before restore: " + e.getMessage());
}
int rows = jdbcTemplate.update(sql, updatedBy, new java.sql.Timestamp(System.currentTimeMillis()), id);
if (rows > 0 && old != null) {
old.put("remarks", "Record restored");
old.put("is_active", 1);
old.put("is_delete", 0);
saveToHistory(old, updatedBy);
}
return rows > 0;
} catch (Exception e) {
System.err.println("Error restoring Tapal detail ID " + id + ": " + e.getMessage());
return false;
}
}
public List<Map<String, Object>> getDeletedTapals() {
String sql = "SELECT t.*, "
+ "c.category_name as resolved_category, "
+ "s.status_name as resolved_status, "
+ "u.usr_name as updated_by_name "
+ "FROM tapal_tracking_details t "
+ "LEFT JOIN tapal_category_list c ON TRIM(t.cat_type_id) REGEXP '^[0-9]+$' AND c.id = CAST(TRIM(t.cat_type_id) AS UNSIGNED) "
+ "LEFT JOIN tapal_status_list s ON TRIM(t.status_id) REGEXP '^[0-9]+$' AND s.id = CAST(TRIM(t.status_id) AS UNSIGNED) "
+ "LEFT JOIN app_user u ON (t.updated_by = CAST(u.usr_id AS CHAR) OR t.updated_by = u.usr_name) "
+ "WHERE t.is_active = 0 AND t.is_delete = 1 "
+ "ORDER BY t.updated_date DESC";
try {
return jdbcTemplate.queryForList(sql);
} catch (Exception e) {
System.err.println("Error fetching deleted Tapal details: " + e.getMessage());
return new ArrayList<>();
}
}
public List<Map<String, Object>> getHistory(String tapalNo) {
String sql = "SELECT h.*, "
+ "c.category_name as resolved_category, "
+ "s.status_name as resolved_status, "
+ "u.usr_name as updated_by_name "
+ "FROM tapal_tracking_details_history h "
+ "LEFT JOIN tapal_category_list c ON TRIM(h.cat_type_id) REGEXP '^[0-9]+$' AND c.id = CAST(TRIM(h.cat_type_id) AS UNSIGNED) "
+ "LEFT JOIN tapal_status_list s ON TRIM(h.status_id) REGEXP '^[0-9]+$' AND s.id = CAST(TRIM(h.status_id) AS UNSIGNED) "
+ "LEFT JOIN app_user u ON (h.updated_by = CAST(u.usr_id AS CHAR) OR h.updated_by = u.usr_name) "
+ "WHERE h.tapal_no = ? "
+ "ORDER BY h.updated_date DESC";
try {
return jdbcTemplate.queryForList(sql, tapalNo);
} catch (Exception e) {
System.err.println("Error fetching Tapal history for tapal_no " + tapalNo + ": " + e.getMessage());
return new ArrayList<>();
}
}
private java.sql.Date parseDate(Object obj) {
if (obj == null || String.valueOf(obj).trim().isEmpty()) {
return null;
}
String str = String.valueOf(obj).trim();
try {
if (str.contains("/")) {
String[] parts = str.split("/");
if (parts.length == 3) {
str = parts[2] + "-" + parts[1] + "-" + parts[0];
}
}
return java.sql.Date.valueOf(str);
} catch (Exception e) {
System.err.println("Error parsing date '" + obj + "' for Tapal: " + e.getMessage());
return null;
}
}
}

12
src/main/java/com/gcc_manpower/gcctonermanagement/controller/TonerController.java

@ -149,6 +149,15 @@ public class TonerController {
return tonerService.getActiveDepartments();
}
@GetMapping("/api/zones")
@ResponseBody
public List<Map<String, Object>> getZones(HttpSession session) {
if (session.getAttribute("toner_usrName") == null) {
return java.util.Collections.emptyList();
}
return tonerService.getActiveZones();
}
@PostMapping("/api/inward")
@ResponseBody
public Map<String, Object> uploadInward(
@ -225,6 +234,7 @@ public class TonerController {
public Map<String, Object> uploadRequest(
@RequestParam("itcellRefNo") String itcellRefNo,
@RequestParam("deptId") String deptId,
@RequestParam("zoneId") String zoneId,
@RequestParam("itemsJson") String itemsJson,
@RequestParam(value = "userRequestFile", required = false) MultipartFile userRequestFile,
HttpSession session) {
@ -273,7 +283,7 @@ public class TonerController {
String urPath = saveUploadedFile(userRequestFile, "user_request", uploadDir);
boolean saved = tonerService.saveUserRequest(
itcellRefNo.trim(), deptId.trim(), items, urPath, updatedBy);
itcellRefNo.trim(), deptId.trim(), zoneId.trim(), items, urPath, updatedBy);
if (saved) {
response.put("success", true);

95
src/main/java/com/gcc_manpower/gcctonermanagement/service/TonerService.java

@ -88,12 +88,16 @@ public class TonerService {
java.sql.Timestamp now = new java.sql.Timestamp(System.currentTimeMillis());
try {
for (Map<String, Object> item : items) {
int pid = Integer.parseInt(String.valueOf(item.get("pid")));
int tid = Integer.parseInt(String.valueOf(item.get("tid")));
Integer pidVal = parseIntegerSafely(item.get("pid"));
Integer tidVal = parseIntegerSafely(item.get("tid"));
if (pidVal == null || tidVal == null) {
continue; // Skip invalid item
}
int pid = pidVal;
int tid = tidVal;
String qty = String.valueOf(item.get("qty"));
Integer requestId = item.get("requestId") != null
? Integer.parseInt(String.valueOf(item.get("requestId")))
: null;
Integer requestId = parseIntegerSafely(item.get("requestId"));
int qtyInt = 0;
try {
@ -126,17 +130,22 @@ public class TonerService {
}
@Transactional
public boolean saveUserRequest(String itCellRefNo, String deptId, List<Map<String, Object>> items,
public boolean saveUserRequest(String itCellRefNo, String deptId, String zoneId, List<Map<String, Object>> items,
String userRequestUpload, String username) {
java.sql.Timestamp now = new java.sql.Timestamp(System.currentTimeMillis());
String sql = "INSERT INTO toner_department_requested_details " +
"(req_no, itcell_ref_no, dept_id, pid, tid, qty_requested, qty_delivered, user_request_upload, cdate, updated_date, updated_by, is_active, is_delete) "
"(req_no, itcell_ref_no, dept_id, zone_id, pid, tid, qty_requested, qty_delivered, user_request_upload, cdate, updated_date, updated_by, is_active, is_delete) "
+
"VALUES (?, ?, ?, ?, ?, ?, '0', ?, ?, ?, ?, 1, 0)";
"VALUES (?, ?, ?, ?, ?, ?, ?, '0', ?, ?, ?, ?, 1, 0)";
try {
for (Map<String, Object> item : items) {
int pid = Integer.parseInt(String.valueOf(item.get("pid")));
int tid = Integer.parseInt(String.valueOf(item.get("tid")));
Integer pidVal = parseIntegerSafely(item.get("pid"));
Integer tidVal = parseIntegerSafely(item.get("tid"));
if (pidVal == null || tidVal == null) {
continue; // Skip invalid item
}
int pid = pidVal;
int tid = tidVal;
String qtyRequested = String.valueOf(item.get("qty"));
String tonerModel = getTonerModelName(tid);
@ -146,7 +155,7 @@ public class TonerService {
int year = java.util.Calendar.getInstance().get(java.util.Calendar.YEAR);
String reqNo = String.format("%s-%d-%04d", cleanModel, year, seqNum);
jdbcTemplate.update(sql, reqNo, itCellRefNo, deptId, String.valueOf(pid), String.valueOf(tid),
jdbcTemplate.update(sql, reqNo, itCellRefNo, deptId, zoneId, String.valueOf(pid), String.valueOf(tid),
qtyRequested, userRequestUpload, now, now, username);
}
return true;
@ -158,13 +167,14 @@ public class TonerService {
}
public List<Map<String, Object>> getPendingRequests() {
String sql = "SELECT r.id, r.req_no, COALESCE(d.dept_name, r.dept_id) AS dept_id, r.pid, r.tid, r.qty_requested, r.qty_delivered, "
String sql = "SELECT r.id, r.req_no, COALESCE(d.dept_name, r.dept_id) AS dept_id, COALESCE(z.zone_name, r.zone_id) AS zone_name, r.pid, r.tid, r.qty_requested, r.qty_delivered, "
+
"p.printer_name, t.model_name " +
"FROM toner_department_requested_details r " +
"LEFT JOIN toner_printer_model_list p ON r.pid = p.id " +
"LEFT JOIN toner_model_list t ON r.tid = t.id " +
"LEFT JOIN toner_department_list d ON CAST(r.dept_id AS SIGNED) = d.id " +
"LEFT JOIN toner_zone_list z ON CAST(r.zone_id AS SIGNED) = z.id " +
"WHERE r.is_active = 1 AND r.is_delete = 0 " +
"AND (r.qty_delivered IS NULL OR CAST(r.qty_delivered AS SIGNED) < CAST(r.qty_requested AS SIGNED)) " +
"ORDER BY r.id DESC";
@ -185,9 +195,12 @@ public class TonerService {
sql = "UPDATE toner_department_requested_details " +
"SET final_delivered_upload = CASE WHEN final_delivered_upload IS NULL OR final_delivered_upload = '' THEN ? ELSE CONCAT(final_delivered_upload, ',', ?) END, "
+
"qty_delivered = CASE WHEN qty_delivered IS NULL OR CAST(qty_delivered AS SIGNED) = 0 THEN ? ELSE qty_delivered END, "
+
"updated_date = ?, updated_by = ? " +
"WHERE id = ?";
rows = jdbcTemplate.update(sql, finalDeliveredUpload, finalDeliveredUpload, now, username, id);
rows = jdbcTemplate.update(sql, finalDeliveredUpload, finalDeliveredUpload, qtyIssued, now, username,
id);
} else {
sql = "UPDATE toner_department_requested_details " +
"SET qty_delivered = CAST(COALESCE(qty_delivered, 0) AS SIGNED) + CAST(? AS SIGNED), " +
@ -270,7 +283,7 @@ public class TonerService {
+ "MAX(s.cdate) AS cdate, COALESCE(MAX(u.usr_name), MAX(s.updated_by)) AS order_by, "
+ "p.printer_name, t.model_name, "
+ "COALESCE((SELECT w.qty_registered FROM toner_workorder_printermodel_qty w WHERE w.ref_no = s.ref_no AND w.pid = s.pid AND w.tid = s.tid AND w.is_active = 1 AND w.is_delete = 0 LIMIT 1), 0) AS qty_workorder_registered, "
+ "COALESCE((SELECT SUM(CAST(mr.qty_registered AS SIGNED)) FROM toner_workorder_model_multiple_request_qty mr INNER JOIN toner_workorder_model_request_details r ON mr.ref_no = r.ref_no WHERE r.ref_no = s.ref_no AND mr.pid = s.pid AND mr.tid = s.tid AND mr.is_active = 1 AND mr.is_delete = 0 AND r.is_active = 1 AND r.is_delete = 0), 0) AS qty_workorder_requested "
+ "COALESCE((SELECT SUM(CAST(mr.qty_registered AS SIGNED)) FROM toner_workorder_model_multiple_request_qty mr INNER JOIN toner_workorder_model_request_details r ON mr.ref_no = r.ref_no AND mr.cdate = r.cdate WHERE r.ref_no = s.ref_no AND mr.pid = s.pid AND mr.tid = s.tid AND mr.is_active = 1 AND mr.is_delete = 0 AND r.is_active = 1 AND r.is_delete = 0), 0) AS qty_workorder_requested "
+ "FROM toner_stock_register_details s "
+ "LEFT JOIN toner_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 "
@ -287,7 +300,7 @@ public class TonerService {
}
public List<Map<String, Object>> getAllUserRequests() {
String sql = "SELECT r.id, r.pid, r.tid, r.req_no, r.itcell_ref_no, COALESCE(d.dept_name, r.dept_id) AS dept_id, r.qty_requested, r.qty_delivered, "
String sql = "SELECT r.id, r.pid, r.tid, r.req_no, r.itcell_ref_no, COALESCE(d.dept_name, r.dept_id) AS dept_id, COALESCE(z.zone_name, r.zone_id) AS zone_name, r.qty_requested, r.qty_delivered, "
+ "r.user_request_upload, r.cdate, r.updated_date, COALESCE(u.usr_name, r.updated_by) AS updated_by, "
+ "p.printer_name, t.model_name "
+ "FROM toner_department_requested_details r "
@ -295,6 +308,7 @@ public class TonerService {
+ "LEFT JOIN toner_model_list t ON CAST(r.tid AS SIGNED) = t.id "
+ "LEFT JOIN app_user u ON CAST(r.updated_by AS SIGNED) = u.usr_id "
+ "LEFT JOIN toner_department_list d ON CAST(r.dept_id AS SIGNED) = d.id "
+ "LEFT JOIN toner_zone_list z ON CAST(r.zone_id AS SIGNED) = z.id "
+ "WHERE r.is_active = 1 AND r.is_delete = 0 "
+ "ORDER BY r.id DESC";
try {
@ -306,13 +320,14 @@ public class TonerService {
}
public List<Map<String, Object>> getOutwardHistory() {
String sql = "SELECT r.id, r.pid, r.tid, r.req_no, r.itcell_ref_no, COALESCE(d.dept_name, r.dept_id) AS dept_id, r.qty_requested, r.qty_delivered, r.final_delivered_upload, r.user_request_upload, r.cdate, r.updated_date, "
String sql = "SELECT r.id, r.pid, r.tid, r.req_no, r.itcell_ref_no, COALESCE(d.dept_name, r.dept_id) AS dept_id, COALESCE(z.zone_name, r.zone_id) AS zone_name, 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 toner_department_requested_details r " +
"LEFT JOIN toner_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 " +
"LEFT JOIN toner_department_list d ON CAST(r.dept_id AS SIGNED) = d.id " +
"LEFT JOIN toner_zone_list z ON CAST(r.zone_id AS SIGNED) = z.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";
@ -392,7 +407,10 @@ public class TonerService {
// Calculate sum of qty_requested
int totalQtyRequested = 0;
for (Map<String, Object> item : items) {
totalQtyRequested += Integer.parseInt(String.valueOf(item.get("qty")));
Integer q = parseIntegerSafely(item.get("qty"));
if (q != null) {
totalQtyRequested += q;
}
}
final int finalTotalQty = totalQtyRequested;
@ -460,7 +478,7 @@ public class TonerService {
+ "WHERE mr.ref_no = w.ref_no AND mr.pid = w.pid AND mr.tid = w.tid AND mr.is_active = 1 AND mr.is_delete = 0), 0) AS qty_already_requested "
+ "FROM toner_workorder_printermodel_qty w "
+ "LEFT JOIN toner_workorder_register_details r ON w.ref_no = r.ref_no "
+ "LEFT JOIN gccpayment_processing_tracker.vendors_list vl ON CAST(r.vendor_name AS SIGNED) = vl.id "
+ "LEFT JOIN payment_vendors_list vl ON CAST(r.vendor_name AS SIGNED) = vl.id "
+ "LEFT JOIN toner_printer_model_list p ON CAST(w.pid AS SIGNED) = p.id "
+ "LEFT JOIN toner_model_list t ON CAST(w.tid AS SIGNED) = t.id "
+ "WHERE w.ref_no = ? AND w.is_active = 1 AND w.is_delete = 0";
@ -483,12 +501,12 @@ public class TonerService {
}
public List<Map<String, Object>> getWorkorderRequests(String refNo) {
String sql = "SELECT mr.id, mr.pid, mr.tid, mr.qty_registered AS qty_requested, r.company_name AS vendor_id, r.cdate, "
String sql = "SELECT mr.id, r.id AS main_request_id, mr.pid, mr.tid, mr.qty_registered AS qty_requested, r.company_name AS vendor_id, r.cdate, "
+ "COALESCE(u.usr_name, r.updated_by) AS updated_by, r.email_copy_upload, p.printer_name, t.model_name, t.part_code, "
+ "COALESCE((SELECT SUM(CAST(sr.qty_registered AS SIGNED)) FROM toner_stock_register_details sr "
+ "WHERE sr.ref_no = r.ref_no AND sr.pid = mr.pid AND sr.tid = mr.tid AND sr.is_active = 1 AND sr.is_delete = 0), 0) AS qty_inward_received "
+ "WHERE sr.ref_no = r.ref_no AND sr.pid = mr.pid AND sr.tid = mr.tid AND sr.request_id = mr.id AND sr.is_active = 1 AND sr.is_delete = 0), 0) AS qty_inward_received "
+ "FROM toner_workorder_model_multiple_request_qty mr "
+ "LEFT JOIN toner_workorder_model_request_details r ON mr.ref_no = r.ref_no "
+ "LEFT JOIN toner_workorder_model_request_details r ON mr.ref_no = r.ref_no AND mr.cdate = r.cdate "
+ "LEFT JOIN toner_printer_model_list p ON CAST(mr.pid AS SIGNED) = p.id "
+ "LEFT JOIN toner_model_list t ON CAST(mr.tid AS SIGNED) = t.id "
+ "LEFT JOIN app_user u ON CAST(r.updated_by AS SIGNED) = u.usr_id "
@ -509,7 +527,7 @@ public class TonerService {
"p.printer_name, t.model_name " +
"FROM toner_workorder_printermodel_qty w " +
"LEFT JOIN toner_workorder_register_details r ON w.ref_no = r.ref_no " +
"LEFT JOIN gccpayment_processing_tracker.vendors_list vl ON CAST(r.vendor_name AS SIGNED) = vl.id " +
"LEFT JOIN payment_vendors_list vl ON CAST(r.vendor_name AS SIGNED) = vl.id " +
"LEFT JOIN toner_printer_model_list p ON CAST(w.pid AS SIGNED) = p.id " +
"LEFT JOIN toner_model_list t ON CAST(w.tid AS SIGNED) = t.id " +
"LEFT JOIN app_user u ON CAST(r.updated_by AS SIGNED) = u.usr_id " +
@ -524,12 +542,12 @@ public class TonerService {
}
public List<Map<String, Object>> getWorkorderModelRequestHistory() {
String sql = "SELECT mr.id, r.ref_no, mr.pid, mr.tid, r.company_name AS vendor_id, "
String sql = "SELECT mr.id, r.id AS main_request_id, r.ref_no, mr.pid, mr.tid, r.company_name AS vendor_id, "
+ "CAST(mr.qty_registered AS SIGNED) AS qty_requested, r.email_copy_upload, "
+ "r.cdate, COALESCE(u.usr_name, r.updated_by) AS order_by, p.printer_name, t.model_name, "
+ "COALESCE((SELECT w.qty_registered FROM toner_workorder_printermodel_qty w WHERE w.ref_no = r.ref_no AND w.pid = mr.pid AND w.tid = mr.tid AND w.is_active = 1 AND w.is_delete = 0 LIMIT 1), 0) AS qty_registered "
+ "FROM toner_workorder_model_multiple_request_qty mr "
+ "LEFT JOIN toner_workorder_model_request_details r ON mr.ref_no = r.ref_no "
+ "LEFT JOIN toner_workorder_model_request_details r ON mr.ref_no = r.ref_no AND mr.cdate = r.cdate "
+ "LEFT JOIN toner_printer_model_list p ON CAST(mr.pid AS SIGNED) = p.id "
+ "LEFT JOIN toner_model_list t ON CAST(mr.tid AS SIGNED) = t.id "
+ "LEFT JOIN app_user u ON CAST(r.updated_by AS SIGNED) = u.usr_id "
@ -552,4 +570,33 @@ public class TonerService {
return new ArrayList<>();
}
}
public List<Map<String, Object>> getActiveZones() {
String sql = "SELECT id, zone_name FROM toner_zone_list WHERE is_active = 1 AND is_delete = 0";
try {
return jdbcTemplate.queryForList(sql);
} catch (Exception e) {
System.err.println("Error fetching active zones: " + e.getMessage());
return new ArrayList<>();
}
}
public JdbcTemplate getJdbcTemplate() {
return this.jdbcTemplate;
}
private Integer parseIntegerSafely(Object val) {
if (val == null) {
return null;
}
String str = String.valueOf(val).trim();
if (str.isEmpty() || "null".equalsIgnoreCase(str) || "undefined".equalsIgnoreCase(str)) {
return null;
}
try {
return Integer.parseInt(str);
} catch (NumberFormatException e) {
return null;
}
}
}

185
src/main/resources/templates/gccadjustmentmanagement/details.html

@ -1046,12 +1046,21 @@
let suffix = '';
if (filterReason !== 'Total' && filterReason !== 'All') {
let reasonLabel = filterReason;
/* Old translation logic commented
if (filterReason === 'AllThreeNotAvail') reasonLabel = 'FI, SE & DC Not Available';
else if (filterReason === 'FINotAvail') reasonLabel = 'FI Not Available';
else if (filterReason === 'SENotDone') reasonLabel = 'Stock Not Available';
else if (filterReason === 'DCNotAvail') reasonLabel = 'DC Not Available';
else if (filterReason === 'FIAvailSEDCProp') reasonLabel = 'FI Available, SE & DC Pending';
else if (filterReason === 'Others') reasonLabel = 'Others';
*/
if (filterReason === 'FIAvail') reasonLabel = 'FI Available';
else if (filterReason === 'FINotAvail') reasonLabel = 'FI Not Available';
else if (filterReason === 'Others') reasonLabel = 'Others';
else if (filterReason === 'AllThreeNotAvail') reasonLabel = 'FI, SE & DC Not Available';
else if (filterReason === 'SENotDone') reasonLabel = 'Stock Not Available';
else if (filterReason === 'DCNotAvail') reasonLabel = 'DC Not Available';
else if (filterReason === 'FIAvailSEDCProp') reasonLabel = 'FI Available, SE & DC Pending';
suffix = ` - Pending: ${reasonLabel}`;
} else {
@ -1112,12 +1121,21 @@
// Reason Badge
if (filterReason !== 'Total' && filterReason !== 'All') {
let reasonLabel = filterReason;
/* Old translation logic commented
if (filterReason === 'AllThreeNotAvail') reasonLabel = 'FI, SE & DC Not Available';
else if (filterReason === 'FINotAvail') reasonLabel = 'FI Not Available';
else if (filterReason === 'StockDone') reasonLabel = 'Stock Registry Done';
else if (filterReason === 'SENotDone') reasonLabel = 'Stock Not Available';
else if (filterReason === 'DCNotAvail') reasonLabel = 'DC Not Available';
else if (filterReason === 'FIAvailSEDCProp') reasonLabel = 'FI Available, SE & DC Pending';
else if (filterReason === 'Others') reasonLabel = 'Others';
*/
if (filterReason === 'FIAvail') reasonLabel = 'FI Available';
else if (filterReason === 'FINotAvail') reasonLabel = 'FI Not Available';
else if (filterReason === 'Others') reasonLabel = 'Others';
else if (filterReason === 'AllThreeNotAvail') reasonLabel = 'FI, SE & DC Not Available';
else if (filterReason === 'SENotDone') reasonLabel = 'Stock Not Available';
else if (filterReason === 'DCNotAvail') reasonLabel = 'DC Not Available';
else if (filterReason === 'FIAvailSEDCProp') reasonLabel = 'FI Available, SE & DC Pending';
html += `<span class="active-filter-badge"><i class="fa-solid fa-triangle-exclamation text-danger"></i>Reason: ${reasonLabel}</span>`;
}
@ -1473,20 +1491,34 @@
const hasSE = !isNullOrEmpty(r.sr_filepath);
const hasDC = !isNullOrEmpty(r.dc_file_path);
/* Old logic commented
if (!hasFI && !hasSE && !hasDC) return 'AllThreeNotAvail';
if (!hasFI && (hasSE || hasDC)) return 'FINotAvail';
if (hasFI && !hasSE && hasDC) return 'SENotDone';
if (hasFI && hasSE && !hasDC) return 'DCNotAvail';
if (hasFI && !hasSE && !hasDC) return 'FIAvailSEDCProp';
return 'Others';
*/
// New logic
if (!hasFI) return 'FINotAvail';
if (hasFI && (!hasSE || !hasDC)) return 'FIAvail';
return 'Others';
};
/* Old counts commented
let allThreeNotAvailCount = basePending.filter(r => getPendingReasonCode(r) === 'AllThreeNotAvail').length;
let fiNotAvailCount = basePending.filter(r => getPendingReasonCode(r) === 'FINotAvail').length;
let seNotDoneCount = basePending.filter(r => getPendingReasonCode(r) === 'SENotDone').length;
let dcNotAvailCount = basePending.filter(r => getPendingReasonCode(r) === 'DCNotAvail').length;
let fiAvailSedcPropCount = basePending.filter(r => getPendingReasonCode(r) === 'FIAvailSEDCProp').length;
let othersCount = basePending.filter(r => getPendingReasonCode(r) === 'Others').length;
*/
// New counts
let fiAvailCount = basePending.filter(r => getPendingReasonCode(r) === 'FIAvail').length;
let fiNotAvailCount = basePending.filter(r => getPendingReasonCode(r) === 'FINotAvail').length;
let othersCount = basePending.filter(r => getPendingReasonCode(r) === 'Others').length;
// Render the quick filter buttons dynamically
const qContainer = document.getElementById('quick-filters-container');
@ -1504,12 +1536,9 @@
let qHtml = '';
qHtml += renderButton('All', 'Total Pending', totalPendingCount, 'primary');
qHtml += renderButton('AllThreeNotAvail', 'FI, SE & DC Not Available', allThreeNotAvailCount, 'danger');
qHtml += renderButton('FINotAvail', 'FI Not Available', fiNotAvailCount, 'warning text-dark');
qHtml += renderButton('StockDone', 'Stock Not Available', seNotDoneCount, 'info');
qHtml += renderButton('DCNotAvail', 'DC Not Available', dcNotAvailCount, 'dark');
qHtml += renderButton('FIAvailSEDCProp', 'FI Available, SE & DC Pending', fiAvailSedcPropCount, 'success');
qHtml += renderButton('Others', 'Others / Remarks', othersCount, 'secondary');
qHtml += renderButton('FIAvail', 'FI Available', fiAvailCount, 'success');
qHtml += renderButton('FINotAvail', 'FI Not Available', fiNotAvailCount, 'danger');
qHtml += renderButton('Others', 'Others', othersCount, 'secondary');
qContainer.innerHTML = qHtml;
}
@ -1812,7 +1841,7 @@
if (modalBody) {
modalBody.innerHTML = `
<div class="row g-3">
<div class="col-md-6 border-end">
<div class="col-md-4 border-end">
<h6 class="fw-bold text-secondary mb-3 border-bottom pb-1">Basic Details</h6>
<p class="mb-2"><strong>Financial Year:</strong> ${fileObj.fin_year || '-'}</p>
<p class="mb-2"><strong>File Number:</strong> ${fileObj.file_data_num || '-'}</p>
@ -1823,31 +1852,123 @@
<p class="mb-2"><strong>File Status (Category):</strong> ${fileObj.file_status || '-'}</p>
<p class="mb-2"><strong>Subject:</strong> ${fileObj.subject || '-'}</p>
</div>
<div class="col-md-6">
<div class="col-md-8">
<h6 class="fw-bold text-secondary mb-3 border-bottom pb-1">Amounts & Files</h6>
<p class="mb-2"><strong>Bal Amount:</strong> ${formatAmount(fileObj.bal_amt)}</p>
<p class="mb-2"><strong>AS File:</strong> ${renderViewIcon(fileObj.as_file_path, 'AS File', fileObj.file_data_num)}</p>
<p class="mb-2"><strong>AS Signed Date:</strong> ${formatDate(fileObj.as_file_gen_date)}</p>
<p class="mb-2"><strong>PO Amount:</strong> ${formatAmount(fileObj.po_amt)}</p>
<p class="mb-2"><strong>PO File:</strong> ${renderViewIcon(fileObj.po_file_path, 'PO File', fileObj.file_data_num)}</p>
<p class="mb-2"><strong>PO completed date:</strong> ${formatDate(fileObj.po_file_gen_date)}</p>
<p class="mb-2"><strong>PI Amount:</strong> ${formatAmount(fileObj.pi_amt)}</p>
<p class="mb-2"><strong>PI File:</strong> ${renderViewIcon(fileObj.pi_file_path, 'PI File', fileObj.file_data_num)}</p>
<p class="mb-2"><strong>PI completed date:</strong> ${formatDate(fileObj.pi_file_gen_date)}</p>
<p class="mb-2"><strong>RTGS File:</strong> ${renderViewIcon(fileObj.rtgs_file_path, 'RTGS File', fileObj.file_data_num)}</p>
<p class="mb-2"><strong>RTGS Date:</strong> ${formatDate(fileObj.rtgs_date)}</p>
<p class="mb-2"><strong>FI Amount:</strong> ${formatAmount(fileObj.fi_amt)}</p>
<p class="mb-2"><strong>FI File:</strong> ${renderViewIcon(fileObj.fi_file_path, 'FI File', fileObj.file_data_num)}</p>
<p class="mb-2"><strong>FI completed date:</strong> ${formatDate(fileObj.fi_file_gen_date)}</p>
<p class="mb-2"><strong>Stock registry File:</strong> ${renderViewIcon(fileObj.sr_filepath, 'SR File', fileObj.file_data_num)}</p>
<p class="mb-2"><strong>DC file:</strong> ${renderViewIcon(fileObj.dc_file_path, 'DC File', fileObj.file_data_num)}</p>
<p class="mb-2"><strong>DC completed date:</strong> ${formatDate(fileObj.dc_completed_date)}</p>
<p class="mb-2"><strong>EJV date:</strong> ${formatDate(fileObj.ejv_num_file_gen_date)}</p>
<p class="mb-2"><strong>EJV File:</strong> ${renderViewIcon(fileObj.ejv_num_file_path, 'EJV File', fileObj.file_data_num)}</p>
<p class="mb-2"><strong>Adjustment Order Final File:</strong> ${renderViewIcon(fileObj.as_final_file_path, 'AS Final File', fileObj.file_data_num)}</p>
<p class="mb-2"><strong>AS Final Date:</strong> ${formatDate(fileObj.as_final_file_gen_date)}</p>
<p class="mb-2"><strong>TC File:</strong> ${renderViewIcon(fileObj.tc_file_path, 'TC File', fileObj.file_data_num)}</p>
<p class="mb-2"><strong>TC Date:</strong> ${formatDate(fileObj.tc_file_gen_date)}</p>
<!-- AS Group -->
<div class="row g-2 mb-3 border-bottom pb-2">
<div class="col-md-4">
<strong class="text-muted" style="font-size: 0.85rem;">Bal Amount:</strong>
<div class="mt-1 fw-semibold text-dark">${formatAmount(fileObj.bal_amt)}</div>
</div>
<div class="col-md-4">
<strong class="text-muted" style="font-size: 0.85rem;">AS File:</strong>
<div class="mt-1">${renderViewIcon(fileObj.as_file_path, 'AS File', fileObj.file_data_num)}</div>
</div>
<div class="col-md-4">
<strong class="text-muted" style="font-size: 0.85rem;">AS Signed Date:</strong>
<div class="mt-1 fw-semibold text-dark">${formatDate(fileObj.as_file_gen_date)}</div>
</div>
</div>
<!-- PI Group -->
<div class="row g-2 mb-3 border-bottom pb-2">
<div class="col-md-4">
<strong class="text-muted" style="font-size: 0.85rem;">PI Amount:</strong>
<div class="mt-1 fw-semibold text-dark">${formatAmount(fileObj.pi_amt)}</div>
</div>
<div class="col-md-4">
<strong class="text-muted" style="font-size: 0.85rem;">PI File:</strong>
<div class="mt-1">${renderViewIcon(fileObj.pi_file_path, 'PI File', fileObj.file_data_num)}</div>
</div>
<div class="col-md-4">
<strong class="text-muted" style="font-size: 0.85rem;">PI completed date:</strong>
<div class="mt-1 fw-semibold text-dark">${formatDate(fileObj.pi_file_gen_date)}</div>
</div>
</div>
<!-- FI Group -->
<div class="row g-2 mb-3 border-bottom pb-2">
<div class="col-md-4">
<strong class="text-muted" style="font-size: 0.85rem;">FI Amount:</strong>
<div class="mt-1 fw-semibold text-dark">${formatAmount(fileObj.fi_amt)}</div>
</div>
<div class="col-md-4">
<strong class="text-muted" style="font-size: 0.85rem;">FI File:</strong>
<div class="mt-1">${renderViewIcon(fileObj.fi_file_path, 'FI File', fileObj.file_data_num)}</div>
</div>
<div class="col-md-4">
<strong class="text-muted" style="font-size: 0.85rem;">FI completed date:</strong>
<div class="mt-1 fw-semibold text-dark">${formatDate(fileObj.fi_file_gen_date)}</div>
</div>
</div>
<!-- RTGS & SR Group -->
<div class="row g-2 mb-3 border-bottom pb-2">
<div class="col-md-4">
<strong class="text-muted" style="font-size: 0.85rem;">RTGS File:</strong>
<div class="mt-1">${renderViewIcon(fileObj.rtgs_file_path, 'RTGS File', fileObj.file_data_num)}</div>
</div>
<div class="col-md-4">
<strong class="text-muted" style="font-size: 0.85rem;">RTGS Date:</strong>
<div class="mt-1 fw-semibold text-dark">${formatDate(fileObj.rtgs_date)}</div>
</div>
<div class="col-md-4">
<strong class="text-muted" style="font-size: 0.85rem;">Stock registry File:</strong>
<div class="mt-1">${renderViewIcon(fileObj.sr_filepath, 'SR File', fileObj.file_data_num)}</div>
</div>
</div>
<!-- DC & EJV Group -->
<div class="row g-2 mb-3 border-bottom pb-2">
<div class="col-md-3">
<strong class="text-muted" style="font-size: 0.85rem;">DC file:</strong>
<div class="mt-1">${renderViewIcon(fileObj.dc_file_path, 'DC File', fileObj.file_data_num)}</div>
</div>
<div class="col-md-3">
<strong class="text-muted" style="font-size: 0.85rem;">DC completed date:</strong>
<div class="mt-1 fw-semibold text-dark">${formatDate(fileObj.dc_completed_date)}</div>
</div>
<div class="col-md-3">
<strong class="text-muted" style="font-size: 0.85rem;">EJV File:</strong>
<div class="mt-1">${renderViewIcon(fileObj.ejv_num_file_path, 'EJV File', fileObj.file_data_num)}</div>
</div>
<div class="col-md-3">
<strong class="text-muted" style="font-size: 0.85rem;">EJV date:</strong>
<div class="mt-1 fw-semibold text-dark">${formatDate(fileObj.ejv_num_file_gen_date)}</div>
</div>
</div>
<!-- Adjustment Final & TC Group -->
<div class="row g-2 mb-3 pb-2">
<div class="col-md-3">
<strong class="text-muted" style="font-size: 0.85rem;">Adjustment Order Final File:</strong>
<div class="mt-1">${renderViewIcon(fileObj.as_final_file_path, 'AS Final File', fileObj.file_data_num)}</div>
</div>
<div class="col-md-3">
<strong class="text-muted" style="font-size: 0.85rem;">AS Final Date:</strong>
<div class="mt-1 fw-semibold text-dark">${formatDate(fileObj.as_final_file_gen_date)}</div>
</div>
<div class="col-md-3">
<strong class="text-muted" style="font-size: 0.85rem;">TC File:</strong>
<div class="mt-1">${renderViewIcon(fileObj.tc_file_path, 'TC File', fileObj.file_data_num)}</div>
</div>
<div class="col-md-3">
<strong class="text-muted" style="font-size: 0.85rem;">TC Date:</strong>
<div class="mt-1 fw-semibold text-dark">${formatDate(fileObj.tc_file_gen_date)}</div>
</div>
</div>
<!-- PurchaseOrder File Group -->
<div class="row g-2 mb-3 border-bottom pb-2">
<div class="col-md-4">
<strong class="text-muted" style="font-size: 0.85rem;">PurchaseOrder File:</strong>
<div class="mt-1">${renderViewIcon(fileObj.po_file_path, 'PO File', fileObj.file_data_num)}</div>
</div>
</div>
</div>
</div>
<div class="row mt-3 border-top pt-3">

142
src/main/resources/templates/gccservicepaymenttracker/dashboard.html

@ -1368,6 +1368,7 @@
<th>Age of Bill (Days)</th>
<th>Status</th>
<th>Remarks</th>
<th>Mail Screenshot</th>
<th>Payment Review</th>
<th onclick="sortMainTable('updated_date')" style="cursor: pointer; user-select: none;">Last
Updated At <span id="main-sort-updated_date-icon"><i class="fa-solid fa-sort ms-1"
@ -1562,6 +1563,21 @@
</div>
</div>
<!-- Screenshot Attachment -->
<div class="col-md-12 mt-3">
<label for="form-screenshot" class="form-label fw-semibold text-secondary">Screenshot
Attachment
(Optional)</label>
<input type="file" class="form-control" id="form-screenshot" accept="image/*">
<div id="form-existing-screenshot-container" class="mt-2" style="display: none;">
<span class="text-secondary fw-semibold">Current Screenshot:</span>
<a id="form-existing-screenshot-link" href="#" target="_blank"
class="ms-1 text-primary fw-bold text-decoration-none">
<i class="fa-solid fa-image"></i> View Screenshot
</a>
</div>
</div>
<!-- Remarks -->
<div class="col-12">
<label for="form-remarks" class="form-label fw-semibold text-secondary">Remarks</label>
@ -2572,6 +2588,17 @@
const dispStatus = String(row.resolved_status || getStatusName(row.status) || '').trim();
let screenshotHtml = '-';
if (row.mail_screenshot_path) {
let imgUrl = row.mail_screenshot_path;
if (contextPath && contextPath.endsWith('/') && imgUrl.startsWith('/')) {
imgUrl = contextPath + imgUrl.substring(1);
} else {
imgUrl = contextPath + imgUrl;
}
screenshotHtml = `<a href="${imgUrl}" target="_blank" class="btn btn-sm btn-outline-info py-0 px-2" style="font-size: 0.75rem; border-color: #06b6d4; color: #06b6d4; display: inline-flex; align-items: center; gap: 4px;" title="View Screenshot"><i class="fa-solid fa-image"></i> View</a>`;
}
tr.innerHTML += `
<td>${formatDate(row.received_date)}</td>
<td>${formatDate(row.invoice_date)}</td>
@ -2584,6 +2611,7 @@
<td>${calculateAgeOfBill(row.received_date)}</td>
<td><span class="status-badge status-${dispStatus.toLowerCase().replace(/\s+/g, '-')}">${text(dispStatus)}</span></td>
<td><small class="text-muted">${text(row.remarks)}</small></td>
<td>${screenshotHtml}</td>
<td><small class="text-muted">${text(row.payment_review)}</small></td>
<td>${formatDateTime(row.updated_date)}</td>
<td class="fw-semibold text-secondary">${text(row.updated_by_name || '-')}</td>
@ -2610,6 +2638,25 @@
tdActions.appendChild(btnViewPdf);
}
if (row.mail_screenshot_path) {
const btnViewScreenshot = document.createElement('button');
btnViewScreenshot.className = 'btn-grid-action btn-outline-info me-1';
btnViewScreenshot.style.border = '1px solid #06b6d4';
btnViewScreenshot.style.color = '#06b6d4';
btnViewScreenshot.innerHTML = '<i class="fa-solid fa-image"></i>';
btnViewScreenshot.title = 'View Screenshot';
btnViewScreenshot.onclick = () => {
let imgUrl = row.mail_screenshot_path;
if (contextPath && contextPath.endsWith('/') && imgUrl.startsWith('/')) {
imgUrl = contextPath + imgUrl.substring(1);
} else {
imgUrl = contextPath + imgUrl;
}
window.open(imgUrl, '_blank');
};
tdActions.appendChild(btnViewScreenshot);
}
// History Button (Available to all logged in users)
const btnHistory = document.createElement('button');
btnHistory.className = 'btn-grid-action btn-outline-secondary me-1';
@ -2841,6 +2888,10 @@
document.getElementById('form-pdf').value = '';
document.getElementById('form-existing-pdf-container').style.display = 'none';
// Reset Screenshot upload elements
document.getElementById('form-screenshot').value = '';
document.getElementById('form-existing-screenshot-container').style.display = 'none';
recordModalObj.show();
}
@ -2984,6 +3035,23 @@
existingPdfContainer.style.display = 'none';
}
// Populate/Reset Screenshot elements
document.getElementById('form-screenshot').value = '';
const existingScreenshotContainer = document.getElementById('form-existing-screenshot-container');
const existingScreenshotLink = document.getElementById('form-existing-screenshot-link');
if (row.mail_screenshot_path) {
existingScreenshotContainer.style.display = 'block';
let imgUrl = row.mail_screenshot_path;
if (contextPath && contextPath.endsWith('/') && imgUrl.startsWith('/')) {
imgUrl = contextPath + imgUrl.substring(1);
} else {
imgUrl = contextPath + imgUrl;
}
existingScreenshotLink.href = imgUrl;
} else {
existingScreenshotContainer.style.display = 'none';
}
recordModalObj.show();
}
@ -3061,10 +3129,44 @@
}
}
// Upload Screenshot if selected
let screenshotPath = originalRecord ? originalRecord.mail_screenshot_path : null;
const screenshotInput = document.getElementById('form-screenshot');
if (screenshotInput && screenshotInput.files && screenshotInput.files.length > 0) {
showLoader(true, 'Uploading Screenshot...');
const formData = new FormData();
formData.append('file', screenshotInput.files[0]);
const csrfHeaders = getCsrfHeaders();
try {
const uploadResponse = await fetch(contextPath + 'gccservicepaymenttracker/api/upload-screenshot', {
method: 'POST',
headers: {
...csrfHeaders
},
body: formData
});
const uploadResult = await uploadResponse.json();
if (uploadResult.success) {
screenshotPath = uploadResult.filePath;
} else {
alert(uploadResult.error || 'Failed to upload Screenshot.');
showLoader(false);
return;
}
} catch (err) {
console.error("Upload error:", err);
alert("Failed to upload Screenshot due to connection error.");
showLoader(false);
return;
}
}
const payload = {
id, received_date, type, vendor_name: vendorName, subject, amount, invoice_no,
receiptno, invoice_date, physical_file_no, tat, status, followup,
myfollowup, order_by, remarks, payment_review, file_path: filePath
myfollowup, order_by, remarks, payment_review, file_path: filePath,
mail_screenshot_path: screenshotPath
};
const csrfHeaders = getCsrfHeaders();
@ -4258,6 +4360,25 @@
tdActions.appendChild(btnViewPdf);
}
if (row.mail_screenshot_path) {
const btnViewScreenshot = document.createElement('button');
btnViewScreenshot.className = 'btn-grid-action btn-outline-info me-1';
btnViewScreenshot.style.border = '1px solid #06b6d4';
btnViewScreenshot.style.color = '#06b6d4';
btnViewScreenshot.innerHTML = '<i class="fa-solid fa-image"></i>';
btnViewScreenshot.title = 'View Screenshot';
btnViewScreenshot.onclick = () => {
let imgUrl = row.mail_screenshot_path;
if (contextPath && contextPath.endsWith('/') && imgUrl.startsWith('/')) {
imgUrl = contextPath + imgUrl.substring(1);
} else {
imgUrl = contextPath + imgUrl;
}
window.open(imgUrl, '_blank');
};
tdActions.appendChild(btnViewScreenshot);
}
// History Button
const btnHistory = document.createElement('button');
btnHistory.className = 'btn-grid-action btn-outline-secondary me-1';
@ -4409,6 +4530,7 @@
<th>Age of Bill (Days)</th>
<th>Status</th>
<th>Remarks</th>
<th>Screenshot Status</th>
<th>Payment Review</th>
<th>Last Updated At</th>
<th>Last Updated By</th>
@ -4495,6 +4617,7 @@
<td>${calculateAgeOfBill(row.received_date)}</td>
<td>${text(dispStatus)}</td>
<td>${text(row.remarks)}</td>
<td>${row.mail_screenshot_path ? 'Screenshot Uploaded' : 'Screenshot not uploaded'}</td>
<td>${text(row.payment_review)}</td>
<td>${formatDateTime(row.updated_date)}</td>
<td>${text(row.updated_by_name || '-')}</td>
@ -4712,8 +4835,7 @@
const dispStatus = String(item.resolved_status || getStatusName(item.status) || '').trim();
// Document button if file path is available
let docBtnHtml = '-';
let docBtnHtml = '';
if (item.file_path) {
let pdfUrl = item.file_path;
if (contextPath && contextPath.endsWith('/') && pdfUrl.startsWith('/')) {
@ -4721,7 +4843,19 @@
} else {
pdfUrl = contextPath + pdfUrl;
}
docBtnHtml = `<a href="${pdfUrl}" target="_blank" class="btn-grid-action btn-grid-pdf"><i class="fa-solid fa-file-pdf"></i></a>`;
docBtnHtml += `<a href="${pdfUrl}" target="_blank" class="btn-grid-action btn-grid-pdf me-1" title="View PDF"><i class="fa-solid fa-file-pdf"></i></a>`;
}
if (item.mail_screenshot_path) {
let imgUrl = item.mail_screenshot_path;
if (contextPath && contextPath.endsWith('/') && imgUrl.startsWith('/')) {
imgUrl = contextPath + imgUrl.substring(1);
} else {
imgUrl = contextPath + imgUrl;
}
docBtnHtml += `<a href="${imgUrl}" target="_blank" class="btn-grid-action btn-outline-info" style="border: 1px solid #06b6d4; color: #06b6d4;" title="View Screenshot"><i class="fa-solid fa-image"></i></a>`;
}
if (!docBtnHtml) {
docBtnHtml = '-';
}
// Resolve type badge

112
src/main/resources/templates/gccservicepaymenttracker/details.html

@ -459,6 +459,7 @@
style="max-width: 90px;">STATUS <span id="sort-resolved_status-icon"
class="sort-icon"><i class="fa-solid fa-sort"></i></span></th>
<th style="min-width: 150px; max-width: 220px;">REMARKS</th>
<th style="min-width: 100px; max-width: 150px;">Mail SCREENSHOT</th>
<th style="min-width: 150px; max-width: 220px;">PAYMENT REVIEW</th>
<th onclick="sortTable('updated_date')" class="cursor-pointer" style="max-width: 90px;">
LAST<br>UPDATED AT <span id="sort-updated_date-icon" class="sort-icon"><i
@ -595,6 +596,21 @@
</div>
</div>
<!-- Screenshot Attachment -->
<div class="col-md-12 mt-3">
<label for="form-screenshot" class="form-label fw-semibold text-secondary">Screenshot
Attachment
(Optional)</label>
<input type="file" class="form-control" id="form-screenshot" accept="image/*">
<div id="form-existing-screenshot-container" class="mt-2" style="display: none;">
<span class="text-secondary fw-semibold">Current Screenshot:</span>
<a id="form-existing-screenshot-link" href="#" target="_blank"
class="ms-1 text-primary fw-bold text-decoration-none">
<i class="fa-solid fa-image"></i> View Screenshot
</a>
</div>
</div>
<div class="col-12">
<label for="form-remarks" class="form-label fw-semibold text-secondary">Remarks</label>
<textarea class="form-control" id="form-remarks" rows="2"
@ -1579,6 +1595,18 @@
actionsGrid.appendChild(btnPdf);
}
// Screenshot Button
if (row.mail_screenshot_path) {
const btnScreenshot = document.createElement('button');
btnScreenshot.className = 'btn-grid-action btn-outline-info';
btnScreenshot.style.border = '1px solid #06b6d4';
btnScreenshot.style.color = '#06b6d4';
btnScreenshot.innerHTML = '<i class="fa-solid fa-image"></i>';
btnScreenshot.title = 'View Screenshot';
btnScreenshot.onclick = () => openPdfFile(row.mail_screenshot_path);
actionsGrid.appendChild(btnScreenshot);
}
// History Button
const btnHistory = document.createElement('button');
btnHistory.className = 'btn-grid-action btn-outline-secondary';
@ -1608,6 +1636,17 @@
tdActions.appendChild(actionsGrid);
let screenshotHtml = '-';
if (row.mail_screenshot_path) {
let imgUrl = row.mail_screenshot_path;
if (contextPath && contextPath.endsWith('/') && imgUrl.startsWith('/')) {
imgUrl = contextPath + imgUrl.substring(1);
} else {
imgUrl = contextPath + imgUrl;
}
screenshotHtml = `<a href="${imgUrl}" target="_blank" class="btn btn-sm btn-outline-info py-0 px-2" style="font-size: 0.75rem; border-color: #06b6d4; color: #06b6d4; display: inline-flex; align-items: center; gap: 4px;" title="View Screenshot"><i class="fa-solid fa-image"></i> View</a>`;
}
tr.innerHTML = `
<td class="text-center fw-semibold text-secondary" style="width: 45px; white-space: nowrap;">${sno}</td>
<td style="width: 80px; white-space: nowrap;">${recDateStr}</td>
@ -1621,6 +1660,7 @@
<td class="text-center fw-bold ${ageDays > 60 ? 'text-danger' : 'text-dark'}" style="max-width: 50px; white-space: nowrap;">${ageDays}</td>
<td class="text-center" style="max-width: 95px;">${statusBadge}</td>
<td style="min-width: 150px; max-width: 220px; word-break: break-word; line-height: 1.35;" title="${escapeHtml(text(row.remarks))}"><small class="text-muted">${escapeHtml(text(row.remarks))}</small></td>
<td>${screenshotHtml}</td>
<td style="min-width: 150px; max-width: 220px; word-break: break-word; line-height: 1.35;" title="${escapeHtml(text(row.payment_review))}"><small class="text-muted">${escapeHtml(text(row.payment_review))}</small></td>
<td style="max-width: 90px; white-space: nowrap;">${updatedSplit}</td>
<td class="fw-semibold text-secondary" style="max-width: 90px; word-break: break-word;">${escapeHtml(text(row.updated_by_name || row.updated_by))}</td>
@ -1738,6 +1778,11 @@
const existingPdfContainer = document.getElementById('form-existing-pdf-container');
if (existingPdfContainer) existingPdfContainer.style.display = 'none';
const screenshotEl = document.getElementById('form-screenshot');
if (screenshotEl) screenshotEl.value = '';
const existingScreenshotContainer = document.getElementById('form-existing-screenshot-container');
if (existingScreenshotContainer) existingScreenshotContainer.style.display = 'none';
if (recordModalObj) recordModalObj.show();
}
@ -1895,6 +1940,24 @@
existingPdfContainer.style.display = 'none';
}
// Screenshot attachment preview
const screenshotEl = document.getElementById('form-screenshot');
if (screenshotEl) screenshotEl.value = '';
const existingScreenshotContainer = document.getElementById('form-existing-screenshot-container');
const existingScreenshotLink = document.getElementById('form-existing-screenshot-link');
if (row.mail_screenshot_path && existingScreenshotContainer && existingScreenshotLink) {
existingScreenshotContainer.style.display = 'block';
let imgUrl = row.mail_screenshot_path;
if (contextPath && contextPath.endsWith('/') && imgUrl.startsWith('/')) {
imgUrl = contextPath + imgUrl.substring(1);
} else {
imgUrl = contextPath + imgUrl;
}
existingScreenshotLink.href = imgUrl;
} else if (existingScreenshotContainer) {
existingScreenshotContainer.style.display = 'none';
}
if (recordModalObj) recordModalObj.show();
}
@ -1967,9 +2030,38 @@
}
}
// Upload Screenshot if selected
let screenshotPath = originalRecord ? originalRecord.mail_screenshot_path : null;
const screenshotInput = document.getElementById('form-screenshot');
if (screenshotInput && screenshotInput.files && screenshotInput.files.length > 0) {
const formData = new FormData();
formData.append('file', screenshotInput.files[0]);
const csrfHeaders = getCsrfHeaders();
try {
const uploadResponse = await fetch(contextPath + 'gccservicepaymenttracker/api/upload-screenshot', {
method: 'POST',
headers: { ...csrfHeaders },
body: formData
});
const uploadResult = await uploadResponse.json();
if (uploadResult.success) {
screenshotPath = uploadResult.filePath;
} else {
alert(uploadResult.error || 'Failed to upload Screenshot.');
return;
}
} catch (err) {
console.error("Upload error:", err);
alert("Failed to upload Screenshot due to connection error.");
return;
}
}
const payload = {
id, received_date, type, vendor_name: vendorName, subject, amount, invoice_no,
receiptno, invoice_date, physical_file_no, status, remarks, payment_review, file_path: filePath
receiptno, invoice_date, physical_file_no, status, remarks, payment_review, file_path: filePath,
mail_screenshot_path: screenshotPath
};
const csrfHeaders = getCsrfHeaders();
@ -2026,7 +2118,7 @@
const tr = document.createElement('tr');
const dispStatus = String(item.resolved_status || getStatusName(item.status) || '').trim();
let docBtnHtml = '-';
let docBtnHtml = '';
if (item.file_path) {
let pdfUrl = item.file_path;
if (contextPath && contextPath.endsWith('/') && pdfUrl.startsWith('/')) {
@ -2034,7 +2126,19 @@
} else {
pdfUrl = contextPath + pdfUrl;
}
docBtnHtml = `<a href="${pdfUrl}" target="_blank" class="btn-grid-action btn-grid-pdf"><i class="fa-solid fa-file-pdf"></i></a>`;
docBtnHtml += `<a href="${pdfUrl}" target="_blank" class="btn-grid-action btn-grid-pdf me-1" title="View PDF"><i class="fa-solid fa-file-pdf"></i></a>`;
}
if (item.mail_screenshot_path) {
let imgUrl = item.mail_screenshot_path;
if (contextPath && contextPath.endsWith('/') && imgUrl.startsWith('/')) {
imgUrl = contextPath + imgUrl.substring(1);
} else {
imgUrl = contextPath + imgUrl;
}
docBtnHtml += `<a href="${imgUrl}" target="_blank" class="btn-grid-action btn-outline-info" style="border: 1px solid #06b6d4; color: #06b6d4;" title="View Screenshot"><i class="fa-solid fa-image"></i></a>`;
}
if (!docBtnHtml) {
docBtnHtml = '-';
}
let typeHtml = getTypeBadge(item.type, item.file_path);
@ -2373,6 +2477,7 @@
"AGE OF BILL (DAYS)": ageDays,
"STATUS": statusName,
"REMARKS": row.remarks || '-',
"SCREENSHOT STATUS": row.mail_screenshot_path ? 'Screenshot Uploaded' : 'Screenshot not uploaded',
"PAYMENT REVIEW": row.payment_review || '-',
"LAST UPDATED AT": updatedDateTime,
"LAST UPDATED BY": row.updated_by_name || row.updated_by || '-'
@ -2396,6 +2501,7 @@
{ wch: 18 }, // AGE OF BILL
{ wch: 25 }, // STATUS
{ wch: 35 }, // REMARKS
{ wch: 22 }, // SCREENSHOT STATUS
{ wch: 35 }, // PAYMENT REVIEW
{ wch: 20 }, // LAST UPDATED AT
{ wch: 18 } // LAST UPDATED BY

4883
src/main/resources/templates/gcctapaldetailsmanagement/dashboard.html
File diff suppressed because it is too large
View File

1962
src/main/resources/templates/gcctapaldetailsmanagement/details.html
File diff suppressed because it is too large
View File

2
src/main/resources/templates/gcctapaldetailsmanagement/login.html

@ -93,7 +93,7 @@
.then(response => response.json())
.then(data => {
if (data.result) {
alert("username: " + data.usrName + "usrPass:" + data.password);
//alert("username: " + data.usrName + "usrPass:" + data.password);
sessionStorage.setItem("tap_usrName", data.usrName);
window.location.href = contextPath + 'gcctapaldetailsmanagement/dashboard';
} else {

2477
src/main/resources/templates/gcctonermanagement/upload.html
File diff suppressed because it is too large
View File

Loading…
Cancel
Save