diff --git a/.DS_Store b/.DS_Store index edfd92d..ec53bb5 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/mobileservice/.DS_Store b/mobileservice/.DS_Store index f8c57b5..bbd68fc 100644 Binary files a/mobileservice/.DS_Store and b/mobileservice/.DS_Store differ diff --git a/mobileservice/pom.xml b/mobileservice/pom.xml index 23308bc..40f9497 100644 --- a/mobileservice/pom.xml +++ b/mobileservice/pom.xml @@ -114,7 +114,13 @@ poi-ooxml 5.2.3 - + + + + com.openhtmltopdf + openhtmltopdf-pdfbox + 1.0.10 + diff --git a/mobileservice/src/.DS_Store b/mobileservice/src/.DS_Store index 547ae1d..173e3b3 100644 Binary files a/mobileservice/src/.DS_Store and b/mobileservice/src/.DS_Store differ diff --git a/mobileservice/src/main/.DS_Store b/mobileservice/src/main/.DS_Store index 4442cff..d179f1f 100644 Binary files a/mobileservice/src/main/.DS_Store and b/mobileservice/src/main/.DS_Store differ diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/MobileServiceApplication.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/MobileServiceApplication.java index c3cd50d..cfa2bd7 100644 --- a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/MobileServiceApplication.java +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/MobileServiceApplication.java @@ -4,8 +4,10 @@ import java.util.TimeZone; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication +@EnableScheduling public class MobileServiceApplication { public static void main(String[] args) { diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/buildingDemolition/controller/BuildingDemolitionController.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/buildingDemolition/controller/BuildingDemolitionController.java new file mode 100644 index 0000000..b3b2e04 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/buildingDemolition/controller/BuildingDemolitionController.java @@ -0,0 +1,64 @@ +package in.gov.chennaicorporation.mobileservice.buildingDemolition.controller; + +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import in.gov.chennaicorporation.mobileservice.buildingDemolition.service.BuildingDemolitionActivity; + +@RequestMapping("/gccofficialapp/api/buildingdemolition/") +@RestController("buildingDemolitionRest") +public class BuildingDemolitionController { + @Autowired + BuildingDemolitionActivity buildingDemolitionService; + + @GetMapping("/list") + public ResponseEntity>> getBuildingList( + @RequestParam String loginId) { + return ResponseEntity.ok(buildingDemolitionService.getBuildingList(loginId)); + } + + @PostMapping("/update") + public ResponseEntity>> updateDetails( + @RequestParam String id, + @RequestParam String status, + @RequestParam String cby, + @RequestParam(required = true) String latitude, + @RequestParam(required = true) String longitude, + @RequestParam(required = true) String remarks, + @RequestParam(required = true) MultipartFile file) { + return ResponseEntity.ok(buildingDemolitionService.updateDetails(id, status, cby, latitude, longitude, remarks, file)); + } + + // Zone wise Report + @GetMapping("/report/zone") + public ResponseEntity>> zoneReport() { + return ResponseEntity.ok(buildingDemolitionService.zoneReport()); + } + + // Ward wise Report (filter by zone) + @GetMapping("/report/ward") + public ResponseEntity>> wardReport(@RequestParam String zone) { + return ResponseEntity.ok(buildingDemolitionService.wardReport(zone)); + } + + // Pending list Report (filter by ward) + @GetMapping("/report/pending") + public ResponseEntity>> pendingReport(@RequestParam String ward) { + return ResponseEntity.ok(buildingDemolitionService.pendingReport(ward)); + } + + // Completed list Report (filter by ward) + @GetMapping("/report/completed") + public ResponseEntity>> completedReport(@RequestParam String ward) { + return ResponseEntity.ok(buildingDemolitionService.completedReport(ward)); + } +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/buildingDemolition/service/BuildingDemolitionActivity.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/buildingDemolition/service/BuildingDemolitionActivity.java new file mode 100644 index 0000000..e6c7adc --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/buildingDemolition/service/BuildingDemolitionActivity.java @@ -0,0 +1,325 @@ +package in.gov.chennaicorporation.mobileservice.buildingDemolition.service; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.SecureRandom; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import javax.imageio.ImageIO; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.stream.ImageOutputStream; +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.core.env.Environment; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Service; +import org.springframework.util.MultiValueMap; +import org.springframework.web.multipart.MultipartFile; + +import in.gov.chennaicorporation.mobileservice.gccactivity.service.DateTimeUtil; + +@Service +public class BuildingDemolitionActivity { + private JdbcTemplate jdbcBuildingDemolitionTemplate; + + private final Environment environment; + private String fileBaseUrl; + + private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + private static final int STRING_LENGTH = 15; + private static final Random RANDOM = new SecureRandom(); + + @Autowired + public void setDataSource(@Qualifier("mysqlGccBuildingDemolitionSource") DataSource BuildingDemolitionDataSource) { + this.jdbcBuildingDemolitionTemplate = new JdbcTemplate(BuildingDemolitionDataSource); + } + + @Autowired + public BuildingDemolitionActivity(Environment environment) { + this.environment = environment; + this.fileBaseUrl=environment.getProperty("fileBaseUrl"); + } + + public static String generateRandomString() { + StringBuilder result = new StringBuilder(STRING_LENGTH); + for (int i = 0; i < STRING_LENGTH; i++) { + result.append(CHARACTERS.charAt(RANDOM.nextInt(CHARACTERS.length()))); + } + return result.toString(); + } + + public static String generateRandomStringForFile(int String_Lenth) { + StringBuilder result = new StringBuilder(String_Lenth); + for (int i = 0; i < STRING_LENGTH; i++) { + result.append(CHARACTERS.charAt(RANDOM.nextInt(CHARACTERS.length()))); + } + return result.toString(); + } + + private byte[] compressImage(BufferedImage image, float quality) throws IOException { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(byteArrayOutputStream); + + ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next(); + writer.setOutput(imageOutputStream); + + ImageWriteParam param = writer.getDefaultWriteParam(); + if (param.canWriteCompressed()) { + param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); + param.setCompressionQuality(quality); + } + + writer.write(null, new javax.imageio.IIOImage(image, null, null), param); + + writer.dispose(); + imageOutputStream.close(); + + return byteArrayOutputStream.toByteArray(); + } + + public String fileUpload(String name, String id, MultipartFile file) { + + int lastInsertId = 0; + // Set the file path where you want to save it + String uploadDirectory = environment.getProperty("file.upload.directory"); + String serviceFolderName = environment.getProperty("buildingdemolition_foldername"); + var year =DateTimeUtil.getCurrentYear(); + var month =DateTimeUtil.getCurrentMonth(); + + uploadDirectory = uploadDirectory + serviceFolderName + year +"/"+month; + + try { + // Create directory if it doesn't exist + Path directoryPath = Paths.get(uploadDirectory); + if (!Files.exists(directoryPath)) { + Files.createDirectories(directoryPath); + } + + // Datetime string + String datetimetxt = DateTimeUtil.getCurrentDateTime(); + // File name + System.out.println(file.getOriginalFilename()); + String fileName = name+ "_" +id + "_" + datetimetxt + "_" + generateRandomStringForFile(10) + "_" + file.getOriginalFilename(); + fileName = fileName.replaceAll("\\s+", ""); // Remove space on filename + + String filePath = uploadDirectory + "/" + fileName; + + String filepath_txt = "/"+serviceFolderName + year + "/" + month + "/" + fileName; + + // Create a new Path object + Path path = Paths.get(filePath); + + // Get the bytes of the file + byte[] bytes = file.getBytes(); + + // Compress the image + BufferedImage image = ImageIO.read(new ByteArrayInputStream(bytes)); + byte[] compressedBytes = compressImage(image, 0.5f); // Compress with 50% quality + + // Write the bytes to the file + Files.write(path, bytes); + + System.out.println(filePath); + return filepath_txt; + + } catch (IOException e) { + e.printStackTrace(); + return "Failed to save file " + file.getOriginalFilename(); + } + } + + public List> getBuildingList(String aeUserId) { + + String sql = "SELECT zone, ward FROM gcc_penalty_hoardings.`hoading_user_list` WHERE userid = ? AND type='ae'"; + List> userList = jdbcBuildingDemolitionTemplate.queryForList(sql, aeUserId); + + if (userList.isEmpty()) { + // You can return an empty list or throw a custom exception + return Collections.emptyList(); // or handle as needed + } + + Map vendorData = userList.get(0); + String ward = String.valueOf(vendorData.get("ward")); + + sql = "SELECT " + + " bd.* " + + "FROM building_demolition bd " + + "LEFT JOIN building_demolition_status bds ON bd.id = bds.bdid " + + "WHERE bds.bdid IS NULL " + + " AND bd.ward = ?"; + List> result = jdbcBuildingDemolitionTemplate.queryForList(sql, ward); + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "Building Demolition List."); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> updateDetails( + String id, + String status, + String cby, + String latitude, + String longitude, + String remarks, + MultipartFile file) { + + String filepath = null; + // 1. Fetch building details + String sql = "SELECT `id` as bdid, `council_resolution_date`, `year`, `zone`, `ward`, " + + "`description`, `category_of_building`, `area_sqm` " + + "FROM `building_demolition` WHERE id=?"; + + List> result = jdbcBuildingDemolitionTemplate.queryForList(sql, id); + + if (result.isEmpty()) { + Map response = new HashMap<>(); + response.put("status", "Failed"); + response.put("message", "No record found for id " + id); + return Collections.singletonList(response); + } + Map building = result.get(0); + + // 2. Check if record already exists in building_demolition_status + String checkSql = "SELECT COUNT(*) FROM `building_demolition_status` WHERE bdid = ?"; + Integer count = jdbcBuildingDemolitionTemplate.queryForObject(checkSql, Integer.class, building.get("bdid")); + + if (count != null && count > 0) { + Map response = new HashMap<>(); + response.put("status", "Failed"); + response.put("message", "Duplicate entry: Demolition status already exists for building id " + id); + return Collections.singletonList(response); + } + + // 2.1. Handle file upload (optional) + if (file != null && !file.isEmpty()) { + filepath = fileUpload(id, cby, file); + } + + // 3. Insert into building_demolition_status + String insertSql = "INSERT INTO `building_demolition_status` " + + "(`bdid`, `council_resolution_date`, `year`, `zone`, `ward`, `description`, " + + "`category_of_building`, `area_sqm`, `status`, `inby`, " + + " `file1`, `remarks`, `latitude`, `longitude`) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + jdbcBuildingDemolitionTemplate.update(insertSql, + building.get("bdid"), + building.get("council_resolution_date"), + building.get("year"), + building.get("zone"), + building.get("ward"), + building.get("description"), + building.get("category_of_building"), + building.get("area_sqm"), + status, + cby, + filepath, + remarks, + latitude, + longitude + ); + + // 4. Build response + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "Building Demolition Status inserted successfully."); + response.put("data", building); + + return Collections.singletonList(response); + } + + // Reports + public List> zoneReport() { + String sqlQuery = "SELECT " + + " bd.zone, " + + " COUNT(bd.id) AS total_building, " + + " SUM(CASE WHEN bds.bdid IS NULL THEN 1 ELSE 0 END) AS pending, " + + " SUM(CASE WHEN bds.bdid IS NOT NULL THEN 1 ELSE 0 END) AS completed " + + "FROM building_demolition bd " + + "LEFT JOIN building_demolition_status bds ON bd.id = bds.bdid " + + "GROUP BY bd.zone " + + "ORDER BY bd.zone"; + + List> result = jdbcBuildingDemolitionTemplate.queryForList(sqlQuery); + + Map response = new HashMap<>(); + response.put("status", 200); + response.put("message", "Zone list report."); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> wardReport(String zone) { + String sqlQuery = "SELECT " + + " bd.ward, " + + " COUNT(bd.id) AS total_building, " + + " SUM(CASE WHEN bds.bdid IS NULL THEN 1 ELSE 0 END) AS pending, " + + " SUM(CASE WHEN bds.bdid IS NOT NULL THEN 1 ELSE 0 END) AS completed " + + "FROM building_demolition bd " + + "LEFT JOIN building_demolition_status bds ON bd.id = bds.bdid " + + "WHERE bd.zone = ? " + + "GROUP BY bd.ward " + + "ORDER BY bd.ward"; + + List> result = jdbcBuildingDemolitionTemplate.queryForList(sqlQuery,zone); + + Map response = new HashMap<>(); + response.put("status", 200); + response.put("message", "Ward list report."); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> pendingReport(String ward) { + String sqlQuery = "SELECT " + + " bd.* " + + "FROM building_demolition bd " + + "LEFT JOIN building_demolition_status bds ON bd.id = bds.bdid " + + "WHERE bds.bdid IS NULL " + + " AND bd.ward = ?"; + + List> result = jdbcBuildingDemolitionTemplate.queryForList(sqlQuery,ward); + + Map response = new HashMap<>(); + response.put("status", 200); + response.put("message", "Pending list report."); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> completedReport(String ward) { + String sqlQuery = "SELECT " + + " bds.*," + + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files', bds.file1) AS image_url " + + "FROM building_demolition bd " + + "INNER JOIN building_demolition_status bds ON bd.id = bds.bdid " + + "WHERE bd.ward = ?"; + + List> result = jdbcBuildingDemolitionTemplate.queryForList(sqlQuery,ward); + + Map response = new HashMap<>(); + response.put("status", 200); + response.put("message", "Completed list report."); + response.put("data", result); + + return Collections.singletonList(response); + } + +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/busshelters/controller/BusShelterController_renovation.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/busshelters/controller/BusShelterController_renovation.java new file mode 100644 index 0000000..91113a1 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/busshelters/controller/BusShelterController_renovation.java @@ -0,0 +1,115 @@ +package in.gov.chennaicorporation.mobileservice.busshelters.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.util.MultiValueMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import in.gov.chennaicorporation.mobileservice.busshelters.service.BusShelterRenovationActivity; + +@RequestMapping("/gccofficialapp/api/busshelter/renovation/") +@RestController("busshelterRenovationRest") +public class BusShelterController_renovation { + @Autowired + private JdbcTemplate jdbcBusShelterTemplate; + @Autowired + private BusShelterRenovationActivity busShelterRenovationActivity; + + @GetMapping(value="/getBusShelterList") + public List getBusShelterList(@RequestParam MultiValueMap formData, + @RequestParam(value = "latitude", required = true) String latitude, + @RequestParam(value = "longitude", required = true) String longitude, + @RequestParam(value = "loginid", required = false) String loginid){ + return busShelterRenovationActivity.getBusShelterList(formData, latitude, longitude, loginid); + } + + @GetMapping(value="/getBusCompletedShelterList") + public List getBusCompletedShelterList(@RequestParam MultiValueMap formData, + @RequestParam(value = "latitude", required = false) String latitude, + @RequestParam(value = "longitude", required = false) String longitude, + @RequestParam(value = "loginid", required = true) String loginid){ + return busShelterRenovationActivity.getBusCompletedShelterList(formData, latitude, longitude, loginid); + } + + @GetMapping(value="/getStageList") // Old App + public List getQuestionsList(@RequestParam(value="loginId", required = false) String cby){ + return busShelterRenovationActivity.getStageList(); + } + + @GetMapping(value="/getBusShelterDetails") + public List getBusShelterDetails( + @RequestParam MultiValueMap formData, + @RequestParam(value="id", required = true) String id, + @RequestParam(value="latitude", required = true) String latitude, + @RequestParam(value="longitude", required = true) String longitude, + @RequestParam(value="loginid", required = false) String loginid, + @RequestParam(value="renovation_required_condition", required = false) String renovation_required_condition){ + return busShelterRenovationActivity.getBusShelterDetails(formData,id,loginid, latitude, longitude, renovation_required_condition); + } + + @PostMapping(value="/saveStageActivityData") + public List saveStageActivityData( + @RequestParam(value="shelter_id", required = true) String shelter_id, + @RequestParam(value="loginId", required = true) String cby, + @RequestParam(value="latitude", required = true) String latitude, + @RequestParam(value="longitude", required = true) String longitude, + @RequestParam(value="zone", required = true) String zone, + @RequestParam(value="ward", required = true) String ward, + @RequestParam(value="streetname", required = false) String streetname, + @RequestParam(value="streetid", required = false) String streetid, + @RequestParam(value="stageid", required = true) String stageid, + @RequestParam(value="remarks", required = true) String remarks, + @RequestParam(value="weightage", required = true) String weightage, + @RequestParam(value="renovation_required", required = false) String renovation_required, + + @RequestParam(value = "file", required = false) MultipartFile file, + @RequestParam(value="stagefile", required = false) MultipartFile stage_file + ){ + return busShelterRenovationActivity.saveStageActivityData(shelter_id, cby, latitude, longitude, zone, ward, + streetname, streetid, stageid, remarks, weightage, file, stage_file, renovation_required); + } + + // Reports + + @GetMapping(value="/getZoneList") + public List getZoneList(){ + return busShelterRenovationActivity.getZoneList(); + } + + @GetMapping(value="/getWardList") + public List getWardList(@RequestParam(value="zone", required = true) String zone){ + return busShelterRenovationActivity.getWardList(zone); + } + + @GetMapping(value="/getVistPendingList") + public List getVistPendingList(@RequestParam(value="ward", required = true) String ward){ + return busShelterRenovationActivity.getVistPendingList(ward); + } + + @GetMapping(value="/getRenovationRequiredList") + public List getRenovationRequiredList(@RequestParam(value="ward", required = true) String ward){ + return busShelterRenovationActivity.getRenovationRequiredList(ward); + } + + @GetMapping(value="/getRenovationNotRequiredList") + public List getRenovationNotRequiredList(@RequestParam(value="ward", required = true) String ward){ + return busShelterRenovationActivity.getRenovationNotRequiredList(ward); + } + + @GetMapping(value="/getWorkPendingList") + public List getWorkPendingList(@RequestParam(value="ward", required = true) String ward){ + return busShelterRenovationActivity.getWorkPendingList(ward); + } + + @GetMapping(value="/getWorkCompletedList") + public List getWorkCompletedList(@RequestParam(value="ward", required = true) String ward){ + return busShelterRenovationActivity.getWorkCompletedList(ward); + } +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/busshelters/service/BusShelterRenovationActivity.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/busshelters/service/BusShelterRenovationActivity.java new file mode 100644 index 0000000..ee9aa6a --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/busshelters/service/BusShelterRenovationActivity.java @@ -0,0 +1,879 @@ +package in.gov.chennaicorporation.mobileservice.busshelters.service; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.SecureRandom; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import javax.imageio.ImageIO; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.stream.ImageOutputStream; +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.core.env.Environment; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.PreparedStatementCreator; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.MultiValueMap; +import org.springframework.web.multipart.MultipartFile; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import in.gov.chennaicorporation.mobileservice.gccactivity.service.DateTimeUtil; + +@Service +public class BusShelterRenovationActivity { + private JdbcTemplate jdbcBusShelterTemplate; + + private final Environment environment; + private String fileBaseUrl; + + private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + private static final int STRING_LENGTH = 15; + private static final Random RANDOM = new SecureRandom(); + + @Autowired + public void setDataSource(@Qualifier("mysqlBusShelterDataSource") DataSource BusShelterDataSource) { + this.jdbcBusShelterTemplate = new JdbcTemplate(BusShelterDataSource); + } + + @Autowired + public BusShelterRenovationActivity(Environment environment) { + this.environment = environment; + this.fileBaseUrl=environment.getProperty("fileBaseUrl"); + } + + public static String generateRandomString() { + StringBuilder result = new StringBuilder(STRING_LENGTH); + for (int i = 0; i < STRING_LENGTH; i++) { + result.append(CHARACTERS.charAt(RANDOM.nextInt(CHARACTERS.length()))); + } + return result.toString(); + } + + public static String generateRandomStringForFile(int String_Lenth) { + StringBuilder result = new StringBuilder(String_Lenth); + for (int i = 0; i < STRING_LENGTH; i++) { + result.append(CHARACTERS.charAt(RANDOM.nextInt(CHARACTERS.length()))); + } + return result.toString(); + } + + private byte[] compressImage(BufferedImage image, float quality) throws IOException { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(byteArrayOutputStream); + + ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next(); + writer.setOutput(imageOutputStream); + + ImageWriteParam param = writer.getDefaultWriteParam(); + if (param.canWriteCompressed()) { + param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); + param.setCompressionQuality(quality); + } + + writer.write(null, new javax.imageio.IIOImage(image, null, null), param); + + writer.dispose(); + imageOutputStream.close(); + + return byteArrayOutputStream.toByteArray(); + } + + public String fileUpload(String name, String id, MultipartFile file) { + + int lastInsertId = 0; + // Set the file path where you want to save it + String uploadDirectory = environment.getProperty("file.upload.directory"); + String serviceFolderName = environment.getProperty("busshelter_renovation_foldername"); + var year =DateTimeUtil.getCurrentYear(); + var month =DateTimeUtil.getCurrentMonth(); + + uploadDirectory = uploadDirectory + serviceFolderName + year +"/"+month; + + try { + // Create directory if it doesn't exist + Path directoryPath = Paths.get(uploadDirectory); + if (!Files.exists(directoryPath)) { + Files.createDirectories(directoryPath); + } + + // Datetime string + String datetimetxt = DateTimeUtil.getCurrentDateTime(); + // File name + System.out.println(file.getOriginalFilename()); + String fileName = name+ "_" +id + "_" + datetimetxt + "_" + generateRandomStringForFile(10) + "_" + file.getOriginalFilename(); + fileName = fileName.replaceAll("\\s+", ""); // Remove space on filename + + String filePath = uploadDirectory + "/" + fileName; + + String filepath_txt = "/"+serviceFolderName + year + "/" + month + "/" + fileName; + + // Create a new Path object + Path path = Paths.get(filePath); + + // Get the bytes of the file + byte[] bytes = file.getBytes(); + + // Compress the image + BufferedImage image = ImageIO.read(new ByteArrayInputStream(bytes)); + byte[] compressedBytes = compressImage(image, 0.5f); // Compress with 50% quality + + // Write the bytes to the file + Files.write(path, bytes); + + System.out.println(filePath); + return filepath_txt; + + } catch (IOException e) { + e.printStackTrace(); + return "Failed to save file " + file.getOriginalFilename(); + } + } + + ////////////////////////////// + public String getConfigValue() { + String sqlQuery = "SELECT `id`, `lat_long_radius` FROM `config` LIMIT 1"; + String value = "50"; // default fallback value + List> results = jdbcBusShelterTemplate.queryForList(sqlQuery); + + if (!results.isEmpty()) { + Map row = results.get(0); + value = String.valueOf(row.get("lat_long_radius")); // corrected key name + } + + return value; + } + + + public String getWardByLoginId(String loginid, String type) { + String sqlQuery = "SELECT `ward` FROM gcc_penalty_hoardings.`hoading_user_list` WHERE `userid` = ? AND `type` = ? LIMIT 1"; + + // Query the database using queryForList + List> results = jdbcBusShelterTemplate.queryForList(sqlQuery, loginid, type); + + // Check if results is not empty and extract the ward value + if (!results.isEmpty()) { + // Extract the ward value from the first result + return (String) results.get(0).get("ward"); + } + + // Handle the case where no result is found + return "000"; // or return null based on your needs + } + + ////////////////////////////// + + public List> getBusShelterList( + MultiValueMap formData, + String latitude, + String longitude, + String loginid + ) { + + String sqlWhere = ""; + + String radius = getConfigValue(); + /* + if (latitude != null && longitude != null && !latitude.isBlank() && !latitude.isEmpty() && !longitude.isBlank() + && !longitude.isEmpty()) { + sqlWhere += " AND ((6371008.8 * acos((cos(radians(" + latitude + + ")) * cos(radians(bsl.latitude)) * cos(radians(bsl.longitude) - radians(" + longitude + + ")) + sin(radians(" + latitude + ")) * sin(radians(bsl.latitude))))) < "+radius+")" + + " ORDER BY" + + " bsl.`id` DESC"; + } + */ + + String ward = getWardByLoginId(loginid,"ae"); + + sqlWhere = " AND (bsr.`stage_status` <> 'Completed' OR bsr.`stage_status` is NULL) ORDER BY bsl.`id` DESC"; + + String sql = "SELECT " + + " bsl.`id`, " + + " bsl.`zone`, " + + " bsl.`ward`, " + + " bsl.`latitude`, " + + " bsl.`longitude`, " + + " bsl.`road`, " + + " bsl.`category`, " + + " bsr.renovation_required, " + + " IF(bsr.shelter_image IS NOT NULL AND bsr.shelter_image != '', " + + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files', bsr.shelter_image), " + + " NULL) AS shelter_image, " + + " COALESCE(bsr.stage_status,'Pending') AS stage_status " + + "FROM `bus_shelter_list` bsl " + + "LEFT JOIN `bus_shelter_renovation` bsr " + + " ON bsr.bsid = bsl.id AND bsr.isactive = 1 " + + "WHERE bsl.isactive = 1 AND bsl.ward = ? "+sqlWhere; + + //System.out.println(sql); + + List> result = jdbcBusShelterTemplate.queryForList(sql,ward); + + ObjectMapper mapper = new ObjectMapper(); + for (Map row : result) { + + Object renovation_required = row.get("renovation_required"); + + if (renovation_required != null) { + sql = "SELECT COALESCE(SUM(`weightage`), 0) AS total_weightage " + + "FROM `bus_shelter_renovation_data` " + + "WHERE bsid = ?"; + + List> presentage = jdbcBusShelterTemplate.queryForList(sql, row.get("id")); + + // Safely get the first result + if (!presentage.isEmpty()) { + row.put("stage_presentage", presentage.get(0).get("total_weightage")); + } else { + row.put("stage_presentage", 0); + } + } else { + row.put("stage_presentage", 0); + } + + } + + + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "Bus Shelter List."); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> getBusCompletedShelterList( + MultiValueMap formData, + String latitude, + String longitude, + String loginid + ) { + + String sqlWhere = ""; + String radius = getConfigValue(); + /* + if (latitude != null && longitude != null && !latitude.isBlank() && !latitude.isEmpty() && !longitude.isBlank() + && !longitude.isEmpty()) { + sqlWhere += " AND ((6371008.8 * acos((cos(radians(" + latitude + + ")) * cos(radians(bsl.latitude)) * cos(radians(bsl.longitude) - radians(" + longitude + + ")) + sin(radians(" + latitude + ")) * sin(radians(bsl.latitude))))) < "+radius+")" + + " ORDER BY" + + " bsl.`id` DESC"; + } + */ + String sql = "SELECT " + + " bsl.`id`, " + + " bsl.`zone`, " + + " bsl.`ward`, " + + " bsl.`latitude`, " + + " bsl.`longitude`, " + + " bsl.`road`, " + + " bsl.`category`, " + + " bsr.renovation_required, " + + " IF(bsr.shelter_image IS NOT NULL AND bsr.shelter_image != '', " + + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files', bsr.shelter_image), " + + " NULL) AS shelter_image, " + + " COALESCE(bsr.stage_status,'Pending') AS stage_status " + + "FROM `bus_shelter_list` bsl " + + "LEFT JOIN `bus_shelter_renovation` bsr " + + " ON bsr.bsid = bsl.id AND bsr.isactive = 1 " + + "WHERE bsl.isactive = 1 AND bsr.stage_status='Completed'"; // +sqlWhere; + + System.out.println(sql); + + List> result = jdbcBusShelterTemplate.queryForList(sql); + + ObjectMapper mapper = new ObjectMapper(); + for (Map row : result) { + + Object renovation_required = row.get("renovation_required"); + + if (renovation_required != null) { + sql = "SELECT COALESCE(SUM(`weightage`), 0) AS total_weightage " + + "FROM `bus_shelter_renovation_data` " + + "WHERE bsid = ?"; + + List> presentage = jdbcBusShelterTemplate.queryForList(sql, row.get("id")); + + // Safely get the first result + if (!presentage.isEmpty()) { + row.put("stage_presentage", presentage.get(0).get("total_weightage")); + } else { + row.put("stage_presentage", 0); + } + } else { + row.put("stage_presentage", 0); + } + + } + + + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "Bus Shelter Completed List."); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> getStageList() { + String sql = "SELECT * FROM `renovation_statge` WHERE isactive=1 ORDER BY orderby"; + List> result = jdbcBusShelterTemplate.queryForList(sql); + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "Bus Shelter Stages."); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> getBusShelterDetails( + MultiValueMap formData, + String id, + String loginid, + String latitude, + String longitude, + String renovation_required_condition + ) { + + String sqlWhere = ""; + //String radius = getConfigValue(); + + String sql = "SELECT " + + " bsl.`id`, " + + " bsl.`zone`, " + + " bsl.`ward`, " + + " bsl.`latitude`, " + + " bsl.`longitude`, " + + " bsl.`road`, " + + " bsl.`category`, " + + " bsr.renovation_required, " + + " IF(bsr.shelter_image IS NOT NULL AND bsr.shelter_image != '', " + + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files', bsr.shelter_image), " + + " NULL) AS shelter_image, " + + " COALESCE(bsr.stage_status,'Pending') AS stage_status " + + "FROM `bus_shelter_list` bsl " + + "LEFT JOIN `bus_shelter_renovation` bsr " + + " ON bsr.bsid = bsl.id AND bsr.isactive = 1 " + + "WHERE bsl.id = ? "; + + System.out.println(sql); + + List> result = jdbcBusShelterTemplate.queryForList(sql, id); + + ObjectMapper mapper = new ObjectMapper(); + for (Map row : result) { + + Object renovation_required = row.get("renovation_required"); + + if (renovation_required != null) { + sql = "SELECT COALESCE(SUM(`weightage`), 0) AS total_weightage " + + "FROM `bus_shelter_renovation_data` " + + "WHERE bsid = ?"; + + List> presentage = jdbcBusShelterTemplate.queryForList(sql, row.get("id")); + + // Safely get the first result + if (!presentage.isEmpty()) { + row.put("stage_presentage", presentage.get(0).get("total_weightage")); + } else { + row.put("stage_presentage", 0); + } + } else { + row.put("stage_presentage", 0); + } + + // Location Check + double shelterLat = Double.parseDouble(row.get("latitude").toString()); + double shelterLng = Double.parseDouble(row.get("longitude").toString()); + double userLat = Double.parseDouble(latitude); + double userLng = Double.parseDouble(longitude); + + // Calculate distance using Haversine formula + double earthRadius = 6371008.8; // in meters + double dLat = Math.toRadians(userLat - shelterLat); + double dLng = Math.toRadians(userLng - shelterLng); + double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + + Math.cos(Math.toRadians(shelterLat)) * Math.cos(Math.toRadians(userLat)) + * Math.sin(dLng / 2) * Math.sin(dLng / 2); + double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + double distance = earthRadius * c; + + double radiusInMeters = Double.parseDouble(getConfigValue()); + row.put("user_on_correct_location", distance <= radiusInMeters); // true if within radius meters + //////// + + if(!"0".equals(renovation_required_condition)) { + + // Stages + List> stageListRaw = getStageList(); + List> stageList = (List>) stageListRaw.get(0).get("data"); + List> stagedata = new ArrayList<>(); + + for (Map stage : stageList) { + Map stageEntry = new HashMap<>(stage); // Clone base stage info + + stageEntry.put("stageid", stage.get("sid")); + stageEntry.put("stage_name", stage.get("name")); + stageEntry.put("weightage", stage.get("weightage")); + stageEntry.put("orderby", stage.get("orderby")); + + sql = "SELECT `dataid`, `bsid`, `stageid`, " + + "CONCAT('"+fileBaseUrl+"/gccofficialapp/files', `image`) AS `image`, " + + "`remarks`, `weightage`, " + + "`zone`, `ward`, `latitude`, `longitude`, `streetname`, `streetid`, " + + " DATE_FORMAT(`cdate`, '%d-%m-%Y') AS `cdate`, " + + "`cby`, `isactive` FROM `bus_shelter_renovation_data` " + + "WHERE `bsid` = ? AND `stageid` = ? AND isactive = 1"; + + List> resultStageData = jdbcBusShelterTemplate.queryForList(sql, row.get("id"), stage.get("sid")); + + if (!resultStageData.isEmpty()) { + Map stageDataRow = resultStageData.get(0); + stageEntry.put("stage_image", stageDataRow.get("image")); + stageEntry.put("stage_remarks", stageDataRow.get("remarks")); + stageEntry.put("stage_date", stageDataRow.get("cdate")); + stageEntry.put("stage_status", "Completed"); + stageEntry.put("stage_presentage", stageDataRow.get("weightage")); + } else { + // Defaults if no data available + stageEntry.put("stage_image", null); + stageEntry.put("stage_remarks", null); + stageEntry.put("stage_date", null); + stageEntry.put("stage_status", "Pending"); + stageEntry.put("stage_presentage", 0); + } + + stagedata.add(stageEntry); + } + row.put("stages", stagedata); + } + + } + + + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "Bus Shelter With Stage Details."); + response.put("data", result); + + return Collections.singletonList(response); + } + + @Transactional + public String addRenovationBaseData( + String shelter_id, String renovation_required, String image, + String latitude, String longitude, String zone, String ward, + String streetname, String streetid, String stage_status + ) { + String sql ="INSERT INTO `bus_shelter_renovation`(" + + "`bsid`, `renovation_required`, `shelter_image`, " + + "`latitude`, `longitude`, `zone`, `ward`, `streetname`, `streetid`, " + + "`stage_status`) " + + "VALUES (?,?,?,?,?,?,?,?,?,?)"; + + jdbcBusShelterTemplate.update(sql, shelter_id, renovation_required, image, latitude, longitude , zone, ward, streetname, streetid, stage_status); + return "success"; + } + + public String updateStageStatus(String shelter_id, String stage_status, String datetxt) { + + String sql = "UPDATE `bus_shelter_renovation` SET `stage_status`=?,`lastcdate` =? WHERE `bsid`=?"; + jdbcBusShelterTemplate.update(sql,stage_status, datetxt, shelter_id); + + return "sussess"; + } + + @Transactional + public List> saveStageActivityData( + String shelter_id, + String cby, + String latitude, + String longitude, + String zone, + String ward, + String streetname, + String streetid, + String stageid, + String remarks, + String weightage, + MultipartFile file, + + MultipartFile stage_file, + String renovation_required) { + List> result = null; + Map response = new HashMap<>(); + int lastInsertId = 0; + + String image = ""; + String stage_image = ""; + + var year = DateTimeUtil.getCurrentYear(); + var month = DateTimeUtil.getCurrentMonth(); + + // Handle file upload if a file is provided + if (file != null && !file.isEmpty()) { + image = fileUpload("bushshelter", shelter_id, file); + } + + // Question Images + if (stage_file != null && !stage_file.isEmpty()) { + stage_image = fileUpload("stage", stageid, stage_file); + } + + String baseimg = image; + + String stage_image_txt = stage_image; + + //String type = // Get before & after + + // Get today's date + LocalDate today = LocalDate.now(); + + // Format it in the desired format (yyyy-MM-dd) + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + String todayDate = today.format(formatter); + + String stage_status = "Pending"; + + if("0".equals(renovation_required) || "1".equals(renovation_required)) { + + addRenovationBaseData(shelter_id, renovation_required, image, latitude, longitude , zone, ward, streetname, streetid, stage_status); + } + if("0".equals(renovation_required)) { + stage_status = "Completed"; + updateStageStatus(shelter_id, stage_status, todayDate); + } + if(!"0".equals(renovation_required)) { + String sqlQuery = "INSERT INTO `bus_shelter_renovation_data`(" + + "`bsid`, `stageid`, `image`, `remarks`, `weightage`, `zone`, " + + "`ward`, `latitude`, `longitude`, `streetname`, `streetid`, `cby`" + + ") " + + "VALUES (?,?,?,?,?,?,?,?,?,?,?,?)"; + + KeyHolder keyHolder = new GeneratedKeyHolder(); + + try { + int affectedRows = jdbcBusShelterTemplate.update(new PreparedStatementCreator() { + @Override + public PreparedStatement createPreparedStatement(Connection connection) throws SQLException { + PreparedStatement ps = connection.prepareStatement(sqlQuery, new String[] { "dataid" }); + ps.setString(1, shelter_id); + ps.setString(2, stageid); + ps.setString(3, stage_image_txt); + ps.setString(4, remarks); + ps.setString(5, weightage); + ps.setString(6, zone); + ps.setString(7, ward); + ps.setString(8, latitude); + ps.setString(9, longitude); + ps.setString(10, streetname); + ps.setString(11, streetid); + ps.setString(12, cby); + + return ps; + } + }, keyHolder); + + if (affectedRows > 0) { + Number generatedId = keyHolder.getKey(); + lastInsertId = (generatedId != null) ? generatedId.intValue() : 0; + response.put("insertId", lastInsertId); + response.put("status", "success"); + response.put("message", "A Bus Shelter stage data was inserted successfully!"); + System.out.println("A Bus Shelter stage data was inserted successfully! Bus Shelter ID: " + generatedId); + + String sql = "SELECT COALESCE(SUM(`weightage`), 0) AS total_weightage " + + "FROM `bus_shelter_renovation_data` " + + "WHERE bsid = ?"; + List> resultStageData = jdbcBusShelterTemplate.queryForList(sql, shelter_id ); + + Object totalWeightageObj = resultStageData.get(0).get("total_weightage"); + double totalWeightage = totalWeightageObj != null ? Double.parseDouble(totalWeightageObj.toString()) : 0; + + if (totalWeightage >= 100) { + stage_status = "Completed"; + } + + updateStageStatus(shelter_id, stage_status, todayDate); + + } else { + response.put("status", "error"); + response.put("message", "Failed to insert a Bus Shelter stage data. Bus Shelter ID:" + shelter_id); + } + + } catch (DataAccessException e) { + System.out.println("Data Access Exception:"); + Throwable rootCause = e.getMostSpecificCause(); + if (rootCause instanceof SQLException) { + SQLException sqlException = (SQLException) rootCause; + System.out.println("SQL State: " + sqlException.getSQLState()); + System.out.println("Error Code: " + sqlException.getErrorCode()); + System.out.println("Message: " + sqlException.getMessage()); + response.put("status", "error"); + response.put("message", sqlException.getMessage()); + response.put("sqlState", sqlException.getSQLState()); + response.put("errorCode", sqlException.getErrorCode()); + } else { + System.out.println("Message: " + rootCause.getMessage()); + response.put("status", "error"); + response.put("message", rootCause.getMessage()); + } + } + } + else { + response.put("insertId", 0); + response.put("status", "success"); + response.put("message", "0 - A Bus Shelter stage data was inserted successfully!"); + } + return Collections.singletonList(response); + } + + // Reports + + public List> getZoneList() { + String sql = "SELECT " + + " bsl.zone, " + + " COUNT(DISTINCT bsl.id) AS total_shelters, " + + " COUNT(DISTINCT CASE WHEN bsr.bsid IS NULL THEN bsl.id END) AS total_not_visited, " + + " COUNT(DISTINCT CASE WHEN bsr.renovation_required = 1 THEN bsr.bsid END) AS total_need_improvement, " + + " COUNT(DISTINCT CASE WHEN bsr.renovation_required = 0 THEN bsr.bsid END) AS total_no_improvement, " + + " COUNT(DISTINCT CASE WHEN bsr.stage_status != 'Completed' AND bsr.stage_status IS NOT NULL THEN bsr.bsid END) AS total_pending, " + + " COUNT(DISTINCT CASE WHEN bsr.stage_status = 'Completed' THEN bsr.bsid END) AS total_completed " + + "FROM " + + " bus_shelter_list bsl " + + "LEFT JOIN " + + " bus_shelter_renovation bsr ON bsr.bsid = bsl.id AND bsr.isactive = 1 " + + "WHERE " + + " bsl.isactive = 1 " + + "GROUP BY " + + " bsl.zone " + + "ORDER BY " + + " bsl.zone"; + List> result = jdbcBusShelterTemplate.queryForList(sql); + // Compute totals + Map totals = new HashMap<>(); + totals.put("zone", "Total"); + + String[] keys = { + "total_shelters", "total_not_visited", + "total_need_improvement", "total_no_improvement", + "total_pending", "total_completed" + }; + + for (String key : keys) { + int sum = result.stream() + .mapToInt(row -> row.get(key) != null ? ((Number) row.get(key)).intValue() : 0) + .sum(); + totals.put(key, sum); + } + // Add totals row at the end + result.add(totals); + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "Bus Shelter Zone Report."); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> getWardList(String zone) { + String sql = "SELECT " + + " bsl.ward," + + " COUNT(DISTINCT bsl.id) AS total_shelters," + + " COUNT(DISTINCT CASE WHEN bsr.bsid IS NULL THEN bsl.id END) AS total_not_visited," + + " COUNT(DISTINCT CASE WHEN bsr.renovation_required = 1 THEN bsr.bsid END) AS total_need_improvement," + + " COUNT(DISTINCT CASE WHEN bsr.renovation_required = 0 THEN bsr.bsid END) AS total_no_improvement," + + " COUNT(DISTINCT CASE WHEN bsr.stage_status != 'Completed' AND bsr.stage_status IS NOT NULL THEN bsr.bsid END) AS total_pending," + + " COUNT(DISTINCT CASE WHEN bsr.stage_status = 'Completed' THEN bsr.bsid END) AS total_completed " + + "FROM " + + " bus_shelter_list bsl " + + "LEFT JOIN " + + " bus_shelter_renovation bsr ON bsr.bsid = bsl.id AND bsr.isactive = 1 " + + "WHERE " + + " bsl.isactive = 1 " + + " AND bsl.zone = ? " + + "GROUP BY " + + " bsl.ward " + + "ORDER BY " + + " bsl.ward"; + List> result = jdbcBusShelterTemplate.queryForList(sql,zone); + // Compute totals + Map totals = new HashMap<>(); + totals.put("ward", "Total"); + + String[] keys = { + "total_shelters", "total_not_visited", + "total_need_improvement", "total_no_improvement", + "total_pending", "total_completed" + }; + + for (String key : keys) { + int sum = result.stream() + .mapToInt(row -> row.get(key) != null ? ((Number) row.get(key)).intValue() : 0) + .sum(); + totals.put(key, sum); + } + + // Add totals row at the end + result.add(totals); + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "Bus Shelter Ward Report."); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> getVistPendingList(String ward) { + String sql = "SELECT bsl.id, bsl.zone, bsl.ward, bsl.road, bsl.latitude, bsl.longitude " + + "FROM bus_shelter_list bsl " + + "LEFT JOIN bus_shelter_renovation bsr ON bsr.bsid = bsl.id AND bsr.isactive = 1 " + + "WHERE bsl.isactive = 1 " + + "AND bsl.ward = ? AND bsr.bsid IS NULL"; + + List> result = jdbcBusShelterTemplate.queryForList(sql, ward); + + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "Bus Shelters not yet visited (pending) in ward " + ward); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> getRenovationRequiredList(String ward) { + String sql = "SELECT bsl.id, bsl.zone, bsl.ward, bsl.road, bsl.latitude, bsl.longitude, bsr.stage_status " + + "FROM bus_shelter_list bsl " + + "LEFT JOIN bus_shelter_renovation bsr ON bsr.bsid = bsl.id AND bsr.isactive = 1 " + + "WHERE bsl.isactive = 1 " + + "AND bsl.ward = ? AND bsr.renovation_required=1"; + + List> result = jdbcBusShelterTemplate.queryForList(sql, ward); + + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "Bus Shelters not yet visited (pending) in ward " + ward); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> getRenovationNotRequiredList(String ward) { + String sql = "SELECT bsl.id, bsl.zone, bsl.ward, bsl.road, bsl.latitude, bsl.longitude, bsr.stage_status " + + "FROM bus_shelter_list bsl " + + "LEFT JOIN bus_shelter_renovation bsr ON bsr.bsid = bsl.id AND bsr.isactive = 1 " + + "WHERE bsl.isactive = 1 " + + "AND bsl.ward = ? AND bsr.renovation_required=0"; + + List> result = jdbcBusShelterTemplate.queryForList(sql, ward); + + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "Bus Shelters improvement Needed List in ward " + ward); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> getWorkPendingList(String ward) { + String sql = "SELECT bsl.id, bsl.zone, bsl.ward, bsl.road, bsl.latitude, bsl.longitude, bsr.stage_status " + + "FROM bus_shelter_list bsl " + + "INNER JOIN bus_shelter_renovation bsr ON bsr.bsid = bsl.id AND bsr.isactive = 1 " + + "WHERE bsl.isactive = 1 " + + "AND bsl.ward = ? AND COALESCE(bsr.stage_status, 'Pending') != 'Completed'"; + + List> result = jdbcBusShelterTemplate.queryForList(sql, ward); + + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "Bus Shelter improvement Not Needed List for ward " + ward); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> getWorkCompletedList(String ward) { + String sql = "SELECT bsl.id, bsl.zone, bsl.ward, bsl.road, bsl.latitude, bsl.longitude, bsr.stage_status " + + "FROM bus_shelter_list bsl " + + "INNER JOIN bus_shelter_renovation bsr ON bsr.bsid = bsl.id AND bsr.isactive = 1 " + + "WHERE bsl.isactive = 1 " + + "AND bsl.ward = ? AND COALESCE(bsr.stage_status, 'Pending') = 'Completed'"; + + List> result = jdbcBusShelterTemplate.queryForList(sql, ward); + + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "Bus Shelter work pending list for ward " + ward); + response.put("data", result); + + return Collections.singletonList(response); + } + + /* + Zone wise: + SELECT + bsl.zone, + COUNT(DISTINCT bsl.id) AS total_shelters, + COUNT(DISTINCT CASE WHEN bsr.bsid IS NULL THEN bsl.id END) AS total_not_visited, + COUNT(DISTINCT CASE WHEN bsr.renovation_required = 1 THEN bsr.bsid END) AS total_need_improvement, + COUNT(DISTINCT CASE WHEN bsr.renovation_required = 0 THEN bsr.bsid END) AS total_no_improvement, + COUNT(DISTINCT CASE WHEN bsr.stage_status != 'Completed' AND bsr.stage_status IS NOT NULL THEN bsr.bsid END) AS total_pending, + COUNT(DISTINCT CASE WHEN bsr.stage_status = 'Completed' THEN bsr.bsid END) AS total_completed +FROM + bus_shelter_list bsl +LEFT JOIN + bus_shelter_renovation bsr ON bsr.bsid = bsl.id AND bsr.isactive = 1 +WHERE + bsl.isactive = 1 +GROUP BY + bsl.zone +ORDER BY + bsl.zone; + + // ward wise + SELECT + bsl.ward, + COUNT(DISTINCT bsl.id) AS total_shelters, + COUNT(DISTINCT CASE WHEN bsr.bsid IS NULL THEN bsl.id END) AS total_not_visited, + COUNT(DISTINCT CASE WHEN bsr.renovation_required = 1 THEN bsr.bsid END) AS total_need_improvement, + COUNT(DISTINCT CASE WHEN bsr.renovation_required = 0 THEN bsr.bsid END) AS total_no_improvement, + COUNT(DISTINCT CASE WHEN bsr.stage_status != 'Completed' AND bsr.stage_status IS NOT NULL THEN bsr.bsid END) AS total_pending, + COUNT(DISTINCT CASE WHEN bsr.stage_status = 'Completed' THEN bsr.bsid END) AS total_completed +FROM + bus_shelter_list bsl +LEFT JOIN + bus_shelter_renovation bsr ON bsr.bsid = bsl.id AND bsr.isactive = 1 +WHERE + bsl.isactive = 1 AND bsl.isdelete = 0 + AND bsl.zone = '01' +GROUP BY + bsl.ward +ORDER BY + bsl.ward; + */ +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/c_d_waste/controller/APIC_D_WasteController.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/c_d_waste/controller/APIC_D_WasteController.java index 0954246..7c85890 100644 --- a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/c_d_waste/controller/APIC_D_WasteController.java +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/c_d_waste/controller/APIC_D_WasteController.java @@ -44,9 +44,10 @@ public class APIC_D_WasteController { @RequestParam(value = "loginId", required = true) String cby, @RequestParam(value = "tonage", required = true) String tonage, @RequestParam(value = "file", required = true) MultipartFile file, - @RequestParam(value = "wastetype", required = true) String type + @RequestParam(value = "wastetype", required = true) String type, + @RequestParam(value = "StreetType", required = false) String StreetType ) { - return c_d_WasteService.saveWaste(cby,latitude,longitude,zone,ward,address,tonage,file, type); + return c_d_WasteService.saveWaste(cby,latitude,longitude,zone,ward,address,tonage,file, type, StreetType); } @PostMapping(value="/saveVendorWaste") @@ -59,9 +60,10 @@ public class APIC_D_WasteController { @RequestParam(value = "ref_id", required = true) String ref_id, @RequestParam(value = "tonage", required = true) int tonage, @RequestParam(value = "file", required = true) MultipartFile file, - @RequestParam(value = "wastetype", required = true) String type + @RequestParam(value = "wastetype", required = true) String type, + @RequestParam(value = "StreetType", required = false) String StreetType ) { - return c_d_WasteService.saveVendorWaste(latitude,longitude,zone,ward,address,tonage,file,type,ref_id); + return c_d_WasteService.saveVendorWaste(latitude,longitude,zone,ward,address,tonage,file,type,ref_id, StreetType); } @GetMapping("/getComplaintList") @@ -220,7 +222,7 @@ public class APIC_D_WasteController { ) { if (requestBy == null || requestBy.isBlank()) { - requestBy = "'Vendor'"; + requestBy = "'Vendor','councillor','IE'"; } else { requestBy = "'"+requestBy+"'"; @@ -238,7 +240,7 @@ public class APIC_D_WasteController { ) { if (requestBy == null || requestBy.isBlank()) { - requestBy = "'Vendor'"; + requestBy = "'Vendor','councillor','IE'"; } else { requestBy = "'"+requestBy+"'"; @@ -258,10 +260,10 @@ public class APIC_D_WasteController { ) { if (requestBy == null || requestBy.isBlank()) { - requestBy = "'Vendor','Officer'"; + requestBy = "'Vendor','Officer','councillor','IE'"; } else { - requestBy = "'"+requestBy+"'"; + //requestBy = "'"+requestBy+"'"; } return c_d_WasteService.getListByStatus(fromDATE,toDATE, zone, ward, status,requestBy); diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/c_d_waste/service/c_d_WasteService.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/c_d_waste/service/c_d_WasteService.java index 3bd29a2..e0ded9b 100644 --- a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/c_d_waste/service/c_d_WasteService.java +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/c_d_waste/service/c_d_WasteService.java @@ -251,7 +251,9 @@ public class c_d_WasteService { + " wlm.`tonage` AS appx_tonage, " + " wt.`name` AS comp_type, " + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files', wlm.`file`) AS image, " - + " wlm.`status` AS comp_status " + + " wlm.`status` AS comp_status, " + + " `street_type` AS comp_street_type, " + + " `kpi` AS comp_kpi " + "FROM " + " `waste_location_mapping` wlm " + "JOIN " @@ -291,7 +293,9 @@ public class c_d_WasteService { + " WHEN `final_vendor_approval` = 'no' THEN 'rejected' " + " ELSE 'pending'" + " END AS approval_status, " - + " DATE_FORMAT(`approved_date`, '%d-%m-%Y %r') AS comp_approved_date " + + " DATE_FORMAT(`approved_date`, '%d-%m-%Y %r') AS comp_approved_date, " + + " `street_type` AS comp_street_type, " + + " `kpi` AS comp_kpi " + "FROM " + " `waste_location_mapping` " + "JOIN " @@ -342,11 +346,21 @@ public class c_d_WasteService { String tonage, //String remarks, MultipartFile file, - String type) { + String type, + String StreetType) { List> result = null; Map response = new HashMap<>(); int lastInsertId = 0; + //KPI Check + String KPI = "2"; + + if("BRR".equalsIgnoreCase(StreetType)) { + KPI = "3"; + } + + String kpi_final = KPI; + String image = ""; // Handle file upload if a file is provided @@ -360,8 +374,8 @@ public class c_d_WasteService { String sqlQuery = "INSERT INTO `waste_location_mapping`" + "(`zone`, `ward`, `cby`, `latitude`, `longitude`, `address`, `tonage`, `file`, " - + "`status`,`type`,`request_by_type`, `approved`, `approvedby`,`final_vendor_approval`,`approved_date`) " - + "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; + + "`status`,`type`,`request_by_type`, `approved`, `approvedby`,`final_vendor_approval`,`approved_date`,`street_type`,`kpi`) " + + "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; KeyHolder keyHolder = new GeneratedKeyHolder(); @@ -418,6 +432,8 @@ public class c_d_WasteService { ps.setString(13, approvedby_final); ps.setString(14, final_vendor_approval_final); ps.setString(15, formattedDate); + ps.setString(16, StreetType); + ps.setString(17, kpi_final); return ps; } }, keyHolder); @@ -465,11 +481,21 @@ public class c_d_WasteService { int tonage, MultipartFile file, String type, - String ref_id) { + String ref_id, + String StreetType) { List> result = null; Map response = new HashMap<>(); int lastInsertId = 0; - + + //KPI Check + String KPI = "1"; + + if("BRR".equalsIgnoreCase(StreetType)) { + KPI = "3"; + } + + String kpi_final = KPI; + String image = ""; // Handle file upload if a file is provided @@ -482,8 +508,8 @@ public class c_d_WasteService { String storeIMG = image; String sqlQuery = "INSERT INTO `waste_location_mapping`" - + "(`zone`, `ward`, `cby`, `latitude`, `longitude`, `address`, `tonage`, `file`, `status`,`type`,`request_by_type`,`ref_id`) " - + "VALUES (?,?,?,?,?,?,?,?,?,?,?,?)"; + + "(`zone`, `ward`, `cby`, `latitude`, `longitude`, `address`, `tonage`, `file`, `status`,`type`,`request_by_type`,`ref_id`,`street_type`,`kpi`) " + + "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; KeyHolder keyHolder = new GeneratedKeyHolder(); @@ -506,6 +532,8 @@ public class c_d_WasteService { ps.setString(10, type); ps.setString(11, "Vendor"); ps.setString(12, ref_id); + ps.setString(13, StreetType); + ps.setString(14, kpi_final); return ps; } }, keyHolder); @@ -665,7 +693,9 @@ public class c_d_WasteService { + " `tonage` AS appx_tonage, " + " wt.`name` AS comp_type, " + " CONCAT('"+fileBaseUrl+"/gccofficialapp/files', `file`) AS image, " - + " `status` AS comp_status " + + " `status` AS comp_status, " + + " `street_type` AS comp_street_type, " + + " `kpi` AS comp_kpi " + "FROM " + " `waste_location_mapping` " + "JOIN " @@ -677,7 +707,8 @@ public class c_d_WasteService { + "WHERE " + " `waste_location_mapping`.isactive = 1 " + " AND `cby`=? " - + "ORDER BY `cdate` DESC"; + + "ORDER BY `cdate` DESC " + + "LIMIT 50"; return jdbcWasteTemplate.queryForList(sql, loginId); } @@ -720,7 +751,9 @@ public class c_d_WasteService { + " `tonage` AS appx_tonage, " + " wt.`name` AS comp_type, " + " CONCAT('"+fileBaseUrl+"/gccofficialapp/files', `file`) AS image, " - + " `status` AS comp_status " + + " `status` AS comp_status, " + + " `street_type` AS comp_street_type, " + + " `kpi` AS comp_kpi " + "FROM " + " `waste_location_mapping` " + "JOIN " @@ -849,7 +882,9 @@ public class c_d_WasteService { + " `tonage` AS appx_tonage, " + " wt.`name` AS comp_type, " + " CONCAT('"+fileBaseUrl+"/gccofficialapp/files', `file`) AS image, " - + " `status` AS comp_status " + + " `status` AS comp_status, " + + " `street_type` AS comp_street_type, " + + " `kpi` AS comp_kpi " + "FROM " + " `waste_location_mapping` " + "JOIN " @@ -1109,7 +1144,7 @@ public class c_d_WasteService { + "WHERE" + " `waste_location_mapping`.isactive = 1 " + " AND DATE(`waste_location_mapping`.cdate) BETWEEN ? AND ? " - //+ " AND `waste_location_mapping`.request_by_type IN ("+requestBy+") " + + " AND `waste_location_mapping`.request_by_type IN ("+requestBy+") " + "GROUP BY" + " `waste_location_mapping`.`zone` " + "WITH ROLLUP"; @@ -1159,7 +1194,7 @@ public class c_d_WasteService { + " `waste_location_mapping`.isactive = 1 " + " AND `waste_location_mapping`.`zone`= ? " + " AND DATE(`waste_location_mapping`.cdate) BETWEEN ? AND ? " - //+ " AND `waste_location_mapping`.request_by_type IN ("+requestBy+") " + + " AND `waste_location_mapping`.request_by_type IN ("+requestBy+") " + "GROUP BY" + " `waste_location_mapping`.`ward` " + "WITH ROLLUP"; @@ -1188,6 +1223,20 @@ public class c_d_WasteService { System.out.println(sqlwhere); } + //System.out.println("Before check: " + requestBy); + + if ("Vendor".equalsIgnoreCase(requestBy)) { + requestBy = "'Vendor','councillor','IE'"; + } + else if ("Officer".equalsIgnoreCase(requestBy)) { + requestBy = "'Officer'"; + } + else { + requestBy = "'"+requestBy+"'"; + } + + //System.out.println("After check: " + requestBy); + String sql = "SELECT " + " wlm.`wlid` AS comp_id, " + " wlm.`zone` AS comp_zone, " @@ -1203,7 +1252,9 @@ public class c_d_WasteService { + " wt.`name` AS comp_type, " + " CASE WHEN wlm.`status` = 'Close' THEN wr.`tonage` ELSE 0 END AS `reply_tonage`, " + " CONCAT('"+fileBaseUrl+"/gccofficialapp/files', wlm.`file`) AS image, " - + " wlm.`status` AS comp_status " + + " wlm.`status` AS comp_status, " + + " wlm.`street_type` AS comp_street_type, " + + " wlm.`kpi` AS comp_kpi " + "FROM " + " `waste_location_mapping` wlm " + "JOIN " diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/configuration/DataSourceConfig.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/configuration/DataSourceConfig.java index f26a612..91b16bc 100644 --- a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/configuration/DataSourceConfig.java +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/configuration/DataSourceConfig.java @@ -192,7 +192,7 @@ public class DataSourceConfig { return dataSource; } - //////////////////////////////(For Schools) //////////////////////// + //////////////////////////////(For Toilets) //////////////////////// @Bean(name = "mysqlToiletsDataSource") public DataSource mysqlToiletsDataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); @@ -281,6 +281,17 @@ public class DataSourceConfig { return dataSource; } + //////////////////////////////(For domestic_waste_management ) //////////////////////// + @Bean(name = "mysqlGccDomesticWasteManagementDataSource") + public DataSource domesticwastemanagement() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); + dataSource.setUrl("jdbc:mysql://"+host+"/domestic_waste_management"); + dataSource.setUsername("root"); + dataSource.setPassword(dbpassword); + return dataSource; + } + //////////////////////////////(For API Application Log) //////////////////////// @Bean(name = "mysqlAPIDataSource") public DataSource mysqlAPIDataSource() { @@ -291,7 +302,84 @@ public class DataSourceConfig { dataSource.setPassword(dbpassword); return dataSource; } - + + //////////////////////////////(For Toilets) //////////////////////// + @Bean(name = "mysqlPrivateToiletsDataSource") + public DataSource mysqlPrivateToiletsDataSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); + dataSource.setUrl("jdbc:mysql://"+host+"/gcc_private_toilets"); + dataSource.setUsername("root"); + dataSource.setPassword(dbpassword); + return dataSource; + } + + //////////////////////////////(For Toilets) //////////////////////// + @Bean(name = "mysqlRoadCutDataSource") + public DataSource mysqlRoadCutDataSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); + dataSource.setUrl("jdbc:mysql://"+host+"/gcc_roadcut"); + dataSource.setUsername("root"); + dataSource.setPassword(dbpassword); + return dataSource; + } + + //////////////////////////////(For PotHole) //////////////////////// + @Bean(name = "mysqlGccPotHoleDataSource") + public DataSource mysqlGccPotHoleDataSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); + dataSource.setUrl("jdbc:mysql://"+host+"/gcc_pothole"); + dataSource.setUsername("root"); + dataSource.setPassword(dbpassword); + return dataSource; + } + + //////////////////////////////(For Construction Guidelines) //////////////////////// + @Bean(name = "mysqlGccConstructionGuidelinesSource") + public DataSource mysqlGccConstructionGuidelinesSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); + dataSource.setUrl("jdbc:mysql://"+host+"/gcc_construction_guidelines"); + dataSource.setUsername("root"); + dataSource.setPassword(dbpassword); + return dataSource; + } + + //////////////////////////////(For View Cutter) //////////////////////// + @Bean(name = "mysqlViewCutterDataSource") + public DataSource mysqlViewCutterDataSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); + dataSource.setUrl("jdbc:mysql://"+host+"/gcc_view_cutter"); + dataSource.setUsername("root"); + dataSource.setPassword(dbpassword); + return dataSource; + } + + //////////////////////////////(For Construction Guidelines) //////////////////////// + @Bean(name = "mysqlGccSpeedBrakeSource") + public DataSource mysqlGccSpeedBrakeSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); + dataSource.setUrl("jdbc:mysql://"+host+"/gcc_speedbrake"); + dataSource.setUsername("root"); + dataSource.setPassword(dbpassword); + return dataSource; + } + + //////////////////////////////(For Construction Guidelines) //////////////////////// + @Bean(name = "mysqlGccBuildingDemolitionSource") + public DataSource mysqlGccBuildingDemolitionSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); + dataSource.setUrl("jdbc:mysql://"+host+"/gcc_building_demolition"); + dataSource.setUsername("root"); + dataSource.setPassword(dbpassword); + return dataSource; + } + ////////////////////////////// ORACLE //////////////////////// @Bean(name = "oracleERPDataSource") public DataSource oracleERPDataSource() { diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/constructionGuidelines/controller/APIController.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/constructionGuidelines/controller/APIController.java new file mode 100644 index 0000000..eed44d3 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/constructionGuidelines/controller/APIController.java @@ -0,0 +1,177 @@ +package in.gov.chennaicorporation.mobileservice.constructionGuidelines.controller; + +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import in.gov.chennaicorporation.mobileservice.constructionGuidelines.service.GuidelinesService; + +@RequestMapping("/gccofficialapp/api/constructionguidelines/") +@RestController("gccofficialappsconstructionguidelines") +public class APIController { + @Autowired + private GuidelinesService guidelinesService; + + @GetMapping(value="/getConstructionList") + public List getToiletsList( + @RequestParam(value="loginId", required = true) String cby, + @RequestParam(value = "latitude", required = true) String latitude, + @RequestParam(value = "longitude", required = true) String longitude + ){ + return guidelinesService.getConstructionList(cby,latitude,longitude); + } + + @GetMapping(value="/getUnitOfficeList") + public List getUnitOfficeList( + @RequestParam(value="zone", required = true) String zone, + @RequestParam(value="ward", required = true) String ward + ){ + return guidelinesService.getUnitOfficeList(zone,ward); + } + + @GetMapping(value="/getBuildingType") + public List getBuildingTypeList(){ + return guidelinesService.getBuildingTypeList(); + } + + @PostMapping(value="/saveDetails") + public List> saveConstructionDetails( + @RequestParam(value = "contractor_name", required = true) String contractorName, + @RequestParam(value = "contractor_mobile", required = true) String contractorMobile, + @RequestParam(value = "buildup_area", required = true) String buildupArea, + @RequestParam(value = "building_type", required = true) String buildingType, + @RequestParam(value = "high_rise", required = true) String highRise, + @RequestParam(value = "zone", required = true) String zone, + @RequestParam(value = "ward", required = true) String ward, + @RequestParam(value = "unit", required = true) String unit, + @RequestParam(value = "under_guidelines", required = true) String underGuidelines, + @RequestParam(value = "site_address", required = true) String siteAddress, + @RequestParam(value = "cby", required = true) String cby, + @RequestParam(value = "latitude", required = true) String latitude, + @RequestParam(value = "longitude", required = true) String longitude, + @RequestParam(value = "mainfile", required = true) MultipartFile mainFile + ){ + return guidelinesService.saveConstructionDetails( + contractorName, contractorMobile, buildupArea, buildingType, highRise, + zone, ward, unit, underGuidelines, siteAddress, cby, latitude, longitude, mainFile + ); + } + + @GetMapping(value="/getguidelines") + public List getGuidelinesList(){ + return guidelinesService.getGuidelinesList(); + } + + @PostMapping(value="/saveFeedback") + public List saveGuidelinesFeedback( + @RequestParam(value = "cdid", required = true) String cdid, + @RequestParam(value = "ciid", required = true) String ciid, + @RequestParam(value = "cby", required = true) String cby, + @RequestParam(value = "latitude", required = true) String latitude, + @RequestParam(value = "longitude", required = true) String longitude, + @RequestParam(value = "zone", required = true) String zone, + @RequestParam(value = "ward", required = true) String ward, + @RequestParam(value = "q1", required = true) String q1, + @RequestParam(value = "q2", required = true) String q2, + @RequestParam(value = "q3", required = true) String q3, + @RequestParam(value = "q4", required = true) String q4, + @RequestParam(value = "q5", required = true) String q5, + @RequestParam(value = "q6", required = true) String q6, + @RequestParam(value = "q7", required = true) String q7, + @RequestParam(value = "q8", required = true) String q8, + @RequestParam(value = "q9", required = true) String q9, + @RequestParam(value = "q10", required = true) String q10, + @RequestParam(value = "q11", required = true) String q11, + @RequestParam(value = "q12", required = true) String q12, + @RequestParam(value = "q13", required = true) String q13, + @RequestParam(value = "q14", required = true) String q14, + @RequestParam(value = "q15", required = true) String q15, + @RequestParam(value = "q16", required = true) String q16, + @RequestParam(value = "q17", required = true) String q17, + @RequestParam(value = "q18", required = true) String q18, + @RequestParam(value = "image1", required = true) MultipartFile image1, + @RequestParam(value = "image2", required = true) MultipartFile image2, + @RequestParam(value = "image3", required = true) MultipartFile image3, + @RequestParam(value = "image4", required = true) MultipartFile image4, + @RequestParam(value = "image5", required = true) MultipartFile image5 + ){ + return guidelinesService.saveGuidlinesFeedback( + cdid, ciid, cby, latitude, longitude, zone, ward, + q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, + q11, q12, q13, q14, q15, q16, q17, q18, + image1, image2, image3, image4, image5 + ); + } + + @GetMapping(value="/getRevisitConstructionList") + public List getRevisitConstructionList( + @RequestParam(value="loginId", required = true) String cby, + @RequestParam(value = "latitude", required = true) String latitude, + @RequestParam(value = "longitude", required = true) String longitude + ){ + return guidelinesService.getRevisitConstructionList(cby,latitude,longitude); + } + + @GetMapping(value="/getRevisitConstructionListWithFeedback") + public List getRevisitConstructionListWithFeedback( + @RequestParam(value="loginId", required = true) String cby, + @RequestParam(value = "cdid", required = true) String cdid, + @RequestParam(value = "ciid", required = true) String ciid + ){ + return guidelinesService.getRevisitConstructionListWithFeedback(cby,cdid,ciid); + } + + @GetMapping(value="/get7thRevisitConstructionList") + public List get7RevisitConstructionList( + @RequestParam(value="loginId", required = true) String cby, + @RequestParam(value = "latitude", required = true) String latitude, + @RequestParam(value = "longitude", required = true) String longitude + ){ + return guidelinesService.getRevisitConstructionList(cby,latitude,longitude); + } + + @PostMapping(value = "/saveAfterNoticeDetails") + public List> saveAfterNoticeDetails( + @RequestParam(value = "cdid", required = true) String cdid, + @RequestParam(value = "ciid", required = true) String ciid, + @RequestParam(value = "giid", required = true) String giid, + @RequestParam(value = "remarks", required = true) String remarks, + @RequestParam(value = "status", required = true) String status, + @RequestParam(value = "zone", required = true) String zone, + @RequestParam(value = "ward", required = true) String ward, + @RequestParam(value = "loginId", required = true) String cby, + @RequestParam(value = "latitude", required = true) String latitude, + @RequestParam(value = "longitude", required = true) String longitude, + @RequestParam(value = "mainfile", required = true) MultipartFile mainfile + ) { + return guidelinesService.saveAfterNoticeDetails( + cdid, ciid, giid, remarks, status, zone, ward, cby, latitude, longitude, mainfile + ); + } + + @PostMapping(value = "/saveFinalNoticeDetails") + public List> saveFinalNoticeDetails( + @RequestParam(value = "cdid", required = true) String cdid, + @RequestParam(value = "ciid", required = true) String ciid, + @RequestParam(value = "giid", required = true) String giid, + @RequestParam(value = "remarks", required = true) String remarks, + @RequestParam(value = "status", required = true) String status, + @RequestParam(value = "zone", required = true) String zone, + @RequestParam(value = "ward", required = true) String ward, + @RequestParam(value = "loginId", required = true) String cby, + @RequestParam(value = "latitude", required = true) String latitude, + @RequestParam(value = "longitude", required = true) String longitude, + @RequestParam(value = "mainfile", required = true) MultipartFile mainfile + ) { + return guidelinesService.saveFinalNoticeDetails( + cdid, ciid, giid, remarks, status, zone, ward, cby, latitude, longitude, mainfile + ); + } +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/constructionGuidelines/controller/package-info.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/constructionGuidelines/controller/package-info.java new file mode 100644 index 0000000..3235da9 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/constructionGuidelines/controller/package-info.java @@ -0,0 +1 @@ +package in.gov.chennaicorporation.mobileservice.constructionGuidelines.controller; \ No newline at end of file diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/constructionGuidelines/package-info.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/constructionGuidelines/package-info.java new file mode 100644 index 0000000..4aca6f3 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/constructionGuidelines/package-info.java @@ -0,0 +1 @@ +package in.gov.chennaicorporation.mobileservice.constructionGuidelines; \ No newline at end of file diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/constructionGuidelines/service/GuidelinesService.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/constructionGuidelines/service/GuidelinesService.java new file mode 100644 index 0000000..87841d2 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/constructionGuidelines/service/GuidelinesService.java @@ -0,0 +1,983 @@ +package in.gov.chennaicorporation.mobileservice.constructionGuidelines.service; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.SecureRandom; +import java.sql.PreparedStatement; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import javax.imageio.ImageIO; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.stream.ImageOutputStream; +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.core.env.Environment; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import in.gov.chennaicorporation.mobileservice.gccactivity.service.DateTimeUtil; + +@Service +public class GuidelinesService { + private JdbcTemplate jdbcGuidlines; + private final Environment environment; + private String fileBaseUrl; + + private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + private static final int STRING_LENGTH = 15; + private static final Random RANDOM = new SecureRandom(); + + @Autowired + public void setDataSource(@Qualifier("mysqlGccConstructionGuidelinesSource") DataSource guidlinesDataSource) { + this.jdbcGuidlines = new JdbcTemplate(guidlinesDataSource); + } + + @Autowired + public GuidelinesService(Environment environment) { + this.environment = environment; + this.fileBaseUrl=environment.getProperty("fileBaseUrl"); + } + + public static String generateRandomString() { + StringBuilder result = new StringBuilder(STRING_LENGTH); + for (int i = 0; i < STRING_LENGTH; i++) { + result.append(CHARACTERS.charAt(RANDOM.nextInt(CHARACTERS.length()))); + } + return result.toString(); + } + + public static String generateRandomFileString(int lenthval) { + StringBuilder result = new StringBuilder(lenthval); + for (int i = 0; i < lenthval; i++) { + result.append(CHARACTERS.charAt(RANDOM.nextInt(CHARACTERS.length()))); + } + return result.toString(); + } + + private byte[] compressImage(BufferedImage image, float quality) throws IOException { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(byteArrayOutputStream); + + ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next(); + writer.setOutput(imageOutputStream); + + ImageWriteParam param = writer.getDefaultWriteParam(); + if (param.canWriteCompressed()) { + param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); + param.setCompressionQuality(quality); + } + + writer.write(null, new javax.imageio.IIOImage(image, null, null), param); + + writer.dispose(); + imageOutputStream.close(); + + return byteArrayOutputStream.toByteArray(); + } + + public String fileUpload(String name, String id, MultipartFile file) { + + int lastInsertId = 0; + // Set the file path where you want to save it + String uploadDirectory = environment.getProperty("file.upload.directory"); + String serviceFolderName = environment.getProperty("construction_guidelines_foldername"); + var year = DateTimeUtil.getCurrentYear(); + var month = DateTimeUtil.getCurrentMonth(); + var date = DateTimeUtil.getCurrentDay(); + + uploadDirectory = uploadDirectory + serviceFolderName + year + "/" + month + "/" + date; + + try { + // Create directory if it doesn't exist + Path directoryPath = Paths.get(uploadDirectory); + if (!Files.exists(directoryPath)) { + Files.createDirectories(directoryPath); + } + + // Datetime string + String datetimetxt = DateTimeUtil.getCurrentDateTime(); + + datetimetxt = datetimetxt + "_"+ generateRandomFileString(6); // Attached Random text + + // File name + String fileName = name + "_" + id + "_" + datetimetxt + "_" + file.getOriginalFilename(); + fileName = fileName.replaceAll("\\s+", ""); // Remove space on filename + + String filePath = uploadDirectory + "/" + fileName; + + String filepath_txt = "/" + serviceFolderName + year + "/" + month + "/" + date + "/" + fileName; + + // Create a new Path object + Path path = Paths.get(filePath); + + // Get the bytes of the file + byte[] bytes = file.getBytes(); + + // Compress the image + BufferedImage image = ImageIO.read(new ByteArrayInputStream(bytes)); + byte[] compressedBytes = compressImage(image, 0.5f); // Compress with 50% quality + + // Write the bytes to the file + Files.write(path, compressedBytes); + + System.out.println(filePath); + return filepath_txt; + + } catch (IOException e) { + e.printStackTrace(); + return "Failed to save file " + file.getOriginalFilename(); + } + } + + public List> getConstructionList(String loginid, + String latitude, + String longitude) { + String sql = "SELECT cd.*" + + ",CONCAT('"+fileBaseUrl+"/gccofficialapp/files',cd.image) AS photo," + + "ci.`ciid`, ci.`under_guidelines`, ci.`penalty` " + + " FROM `construction_details` cd " + + "LEFT JOIN `construction_inspection` ci ON ci.cdid=cd.cdid " + + "WHERE cd.`isactive`=1 AND ci.`isactive`=1"; + List> result = jdbcGuidlines.queryForList(sql); + + for (Map row : result) { + String downloadLink =""; + if(row.get("penalty") != null) { + downloadLink = "https://gccservices.in/gccofficialapp/api/pdf/template?" + + "cdid="+row.get("cdid") + + "&ciid="+row.get("ciid"); + } + row.put("downloadNoticeLink", downloadLink); + } + + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "Construction List."); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> getBuildingTypeList() { + String sql = "SELECT * FROM `building_type_master` WHERE `isactive`=1"; + List> result = jdbcGuidlines.queryForList(sql); + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "Building Type List."); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> getUnitOfficeList(String zone, String ward) { + String sql = "SELECT * FROM `unit_office_master` WHERE `zone`=? AND `ward`=?"; + List> result = jdbcGuidlines.queryForList(sql,zone, ward); + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "Unit Office List."); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> getGuidelinesList() { + String sql = "SELECT * FROM `guidelines` WHERE `isactive`=1 ORDER BY `orderby`"; + List> result = jdbcGuidlines.queryForList(sql); + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "Unit Office List."); + response.put("data", result); + + return Collections.singletonList(response); + } + + @Transactional + public List> saveConstructionDetails( + String contractor_name, + String contractor_mobile, + String buildup_area, + String building_type, + String high_rise, + String zone, + String ward, + String unit, + String under_guidelines, + String site_address, + String cby, + String latitude, + String longitude, + MultipartFile mainfile + ) { + Map response = new HashMap<>(); + List> result = new ArrayList<>(); + + String constimg = fileUpload("Construction", "main", mainfile); + + String type = ""; + + // Prepare question image uploads + MultipartFile[] files = { + mainfile + }; + + // Insert query + String insertSql = "INSERT INTO `construction_details`(`contractor_name`, `contractor_mobile`, `buildup_area`, " + + "`building_type`, `high_rise`, `zone`, `ward`, `unit`, `site_address`, `cby`, `latitude`, `longitude`, " + + "`image`) VALUES " + + "(?,?,?,?,?,?,?,?,?,?,?,?,?)"; + + KeyHolder keyHolder = new GeneratedKeyHolder(); + + int affectedRows = jdbcGuidlines.update(connection -> { + PreparedStatement ps = connection.prepareStatement(insertSql, new String[]{"cdid"}); + int i = 1; + ps.setString(i++, contractor_name); + ps.setString(i++, contractor_mobile); + ps.setString(i++, buildup_area); + ps.setString(i++, building_type); + ps.setString(i++, high_rise); + ps.setString(i++, zone); + ps.setString(i++, ward); + ps.setString(i++, unit); + ps.setString(i++, site_address); + ps.setString(i++, cby); + ps.setString(i++, latitude); + ps.setString(i++, longitude); + ps.setString(i++, constimg); + return ps; + }, keyHolder); + + if (affectedRows > 0) { + int lastInsertId = keyHolder.getKey().intValue(); + int cdid = saveConstructionInspection(lastInsertId, under_guidelines, cby); + if(cdid>0) { + response.put("insertId", lastInsertId); + response.put("status", "success"); + response.put("message", "New Construction details inserted successfully."); + } + else { + response.put("status", "error"); + response.put("message", "New Construction details insert failed."); + } + + } else { + response.put("status", "error"); + response.put("message", "New Construction details insert failed."); + } + + result.add(response); + return result; + } + + @Transactional + public int saveConstructionInspection(int cdid, String under_guidelines, String cby) { + int ciid = 0; + // Insert query + String insertSql = "INSERT INTO `construction_inspection`(`cdid`, `under_guidelines`, `cby`) VALUES " + + "(?,?,?)"; + + KeyHolder keyHolder = new GeneratedKeyHolder(); + + int affectedRows = jdbcGuidlines.update(connection -> { + PreparedStatement ps = connection.prepareStatement(insertSql, new String[]{"ciid"}); + int i = 1; + ps.setInt(i++, cdid); + ps.setString(i++, under_guidelines); + ps.setString(i++, cby); + return ps; + }, keyHolder); + + if (affectedRows > 0) { + int lastInsertId = keyHolder.getKey().intValue(); + ciid = lastInsertId; + } else { + // ❗ Rollback action: mark the original cdid as inactive + String updateSql = "UPDATE `construction_details` SET `isactive` = 0 WHERE `cdid` = ?"; + jdbcGuidlines.update(updateSql, cdid); + } + return ciid; + } + + @Transactional + public List> saveGuidlinesFeedback( + String cdid, + String ciid, + String cby, + String latitude, + String longitude, + String zone, + String ward, + String q1, String q2, String q3, String q4, String q5, String q6, String q7, String q8, String q9, String q10, + String q11, String q12, String q13, String q14, String q15, String q16, String q17, String q18, + MultipartFile image1, MultipartFile image2, MultipartFile image3, MultipartFile image4, MultipartFile image5 + ) { + Map response = new HashMap<>(); + List> result = new ArrayList<>(); + + String type = ""; + + // Prepare question image uploads + MultipartFile[] files = { + image1, image2, image3, image4, image5 + }; + String[] imagePaths = new String[5]; + for (int i = 0; i < files.length; i++) { + if (files[i] != null && !files[i].isEmpty()) { + imagePaths[i] = fileUpload(cdid, "_"+ciid+"_"+(i + 1), files[i]); + } else { + imagePaths[i] = ""; + } + } + + // Insert query + String insertSql = "INSERT INTO `guildelines_inspection` " + + "(`cdid`, `ciid`, `cby`, `latitude`, `longitude`, `zone`, `ward`," + + "`q1`, `q2`, `q3`, `q4`, `q5`, `q6`, `q7`, `q8`, `q9`, `q10`, " + + "`q11`, `q12`, `q13`, `q14`, `q15`, `q16`, `q17`, `q18`, " + + "`img1`, `img2`, `img3`, `img4`, `img5`) " + + "VALUES (" + "?,".repeat(7 + 18 + 5).replaceAll(",$", "") + ")"; + + KeyHolder keyHolder = new GeneratedKeyHolder(); + + int affectedRows = jdbcGuidlines.update(connection -> { + PreparedStatement ps = connection.prepareStatement(insertSql, new String[]{"giid"}); + int i = 1; + ps.setString(i++, cdid); + ps.setString(i++, ciid); + ps.setString(i++, cby); + ps.setString(i++, latitude); + ps.setString(i++, longitude); + ps.setString(i++, zone); + ps.setString(i++, ward); + + // 18 question answers + for (String q : new String[]{q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, + q11, q12, q13, q14, q15, q16, q17, q18}) { + ps.setString(i++, q); + } + + // 5 image paths + for (String path : imagePaths) { + ps.setString(i++, path); + } + + return ps; + }, keyHolder); + + if (affectedRows > 0) { + int lastInsertId = keyHolder.getKey().intValue(); + response.put("insertId", lastInsertId); + // Get penalty type + String penalty= findPenaltyType(q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, + q11, q12, q13, q14, q15, q16, q17, q18); + + if(updateConstructionInspection(lastInsertId, ciid, cdid, penalty)) { + response.put("status", "success"); + response.put("message", "Feedback inserted successfully."); + } + else { + response.put("status", "error"); + response.put("message", "Feedback Insert failed."); + } + } else { + response.put("status", "error"); + response.put("message", "Insert failed."); + } + + result.add(response); + return result; + } + + @Transactional + public boolean updateConstructionInspection(int giid, String ciid, String cdid, String penalty) { + String updateCISql = "UPDATE `construction_inspection` SET `penalty` = ? WHERE ciid = ? AND cdid = ?"; + + int affectedRows = jdbcGuidlines.update(updateCISql, penalty, ciid, cdid); + + if (affectedRows > 0) { + return true; + } else { + // Optional rollback: mark original inspection inactive + String updateSql = "UPDATE `guildelines_inspection` SET `isactive` = 0 WHERE giid = ?"; + jdbcGuidlines.update(updateSql, giid); + return false; + } + } + + private String findPenaltyType(String q1, String q2, String q3, String q4, String q5, String q6, String q7, String q8, String q9, String q10, + String q11, String q12, String q13, String q14, String q15, String q16, String q17, String q18) { + // Check High Penalty: any of q1–q14 is "No" + if ("No".equalsIgnoreCase(q1) || "No".equalsIgnoreCase(q2) || "No".equalsIgnoreCase(q3) || + "No".equalsIgnoreCase(q4) || "No".equalsIgnoreCase(q5) || "No".equalsIgnoreCase(q6) || + "No".equalsIgnoreCase(q7) || "No".equalsIgnoreCase(q8) || "No".equalsIgnoreCase(q9) || + "No".equalsIgnoreCase(q10) || "No".equalsIgnoreCase(q11) || "No".equalsIgnoreCase(q12) || + "No".equalsIgnoreCase(q13) || "No".equalsIgnoreCase(q14)) + { + return "High"; + } + // Check Medium Penalty: any of q15–q17 is "No" + if("No".equalsIgnoreCase(q15) || "No".equalsIgnoreCase(q16) || "No".equalsIgnoreCase(q17)) + { + return "Medium"; + } + // Default to Low Penalty + return "Low"; + } + /* + public List> getRevisitConstructionList(String loginid, String latitude, String longitude) { + String sql = "SELECT cd.*, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', cd.image) AS photo, " + + "ci.ciid, ci.under_guidelines, ci.penalty " + + "FROM construction_details cd " + + "LEFT JOIN construction_inspection ci ON ci.cdid = cd.cdid " + + "WHERE cd.isactive = 1 AND ci.isactive = 1 AND ci.penalty IN ('High','Medium','Low')"; + + List> result = jdbcGuidlines.queryForList(sql); + + for (Map row : result) { + + Boolen allowRevisit = false; + Object cdate = row.get("cdate"); + Object finalDate = cdate + 15 Days + if(finalDate>todaydate) { + allowRevisit = true; + } + row.put("allowRevisit", allowRevisit); + + String downloadLink = "https://gccservices.in/gccofficialapp/api/pdf/template?" + + "cdid="+row.get("cdid") + + "&ciid="+row.get("ciid"); + + row.put("downloadNoticeLink", downloadLink); + } + + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "Construction List with Guidelines & Answers."); + response.put("data", result); + + return Collections.singletonList(response); + } + */ + + public List> getRevisitConstructionList(String loginid, String latitude, String longitude) { + String sql = "SELECT cd.*, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', cd.image) AS photo, " + + "ci.ciid, ci.under_guidelines, ci.penalty " + + "FROM construction_details cd " + + "LEFT JOIN construction_inspection ci ON ci.cdid = cd.cdid " + + "WHERE cd.isactive = 1 AND ci.isactive = 1 AND ci.penalty IN ('High','Medium','Low')" + + "AND cd.cdid NOT IN ( " + + " SELECT cdid " + + " FROM after_notice_inspection " + + " WHERE isactive = 1 " + + " )"; + + List> result = jdbcGuidlines.queryForList(sql); + + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + LocalDate today = LocalDate.now(); + + for (Map row : result) { + Boolean allowRevisit = false; + Object cdateObj = row.get("cdate"); + /* + if (cdateObj != null) { + System.err.println("Raw cdate type: " + cdateObj.getClass().getName() + " | value: " + cdateObj); + } + */ + + if (cdateObj != null) { + LocalDate cdate = null; + + if (cdateObj instanceof LocalDate) { + cdate = (LocalDate) cdateObj; + } else if (cdateObj instanceof java.sql.Date) { + cdate = ((java.sql.Date) cdateObj).toLocalDate(); + } else if (cdateObj instanceof java.sql.Timestamp) { + cdate = ((java.sql.Timestamp) cdateObj).toLocalDateTime().toLocalDate(); + } else if (cdateObj instanceof LocalDateTime) { + cdate = ((LocalDateTime) cdateObj).toLocalDate(); // ✅ FIX + } else if (cdateObj instanceof String) { + try { + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + cdate = LocalDateTime.parse((String) cdateObj, dtf).toLocalDate(); + } catch (Exception e) { + System.err.println("❌ Could not parse cdate: " + cdateObj); + } + } + + if (cdate != null) { + LocalDate finalDate = cdate.plusDays(15); + allowRevisit = !today.isBefore(finalDate); // true if today >= finalDate +/* + System.err.println("ID: " + row.get("cdid") + + " | finalDate: " + finalDate + + " | today: " + today + + " | allowRevisit: " + allowRevisit); + /* + if (finalDate.isBefore(today) || finalDate.isEqual(today)) { + allowRevisit = true; + } + */ + } + } + + row.put("allowRevisit", allowRevisit); + + String downloadLink = "https://gccservices.in/gccofficialapp/api/pdf/template?" + + "cdid=" + row.get("cdid") + + "&ciid=" + row.get("ciid"); + + row.put("downloadNoticeLink", downloadLink); + } + + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "Construction List with Guidelines & Answers."); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> getRevisitConstructionListWithFeedback(String loginid, String cdidtxt, String ciidtxt) { + String sql = "SELECT cd.*, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', cd.image) AS photo, " + + "DATE_FORMAT(cd.cdate, '%d-%m-%Y') AS ddate, " + + "ci.ciid, ci.under_guidelines, ci.penalty " + + "FROM construction_details cd " + + "LEFT JOIN construction_inspection ci ON ci.cdid = cd.cdid " + + "WHERE cd.isactive = 1 AND ci.isactive = 1 AND ci.penalty IN ('High','Medium','Low') AND cd.cdid=? AND ci.ciid=?"; + + List> result = jdbcGuidlines.queryForList(sql, cdidtxt, ciidtxt); + + // Fetch master guideline list only once + String guidelinesSql = "SELECT `gid`, `guideline`, `significance`, `orderby`, `isactive` FROM guidelines WHERE isactive = 1 ORDER BY orderby"; + List> guidelineList = jdbcGuidlines.queryForList(guidelinesSql); + + for (Map row : result) { + Object cdid = row.get("cdid"); + Object ciid = row.get("ciid"); + + // Fetch answer row for this cdid + ciid + String ansSql = "SELECT `giid`, `cdate`, `q1`, `q2`, `q3`, `q4`, `q5`, `q6`, `q7`, `q8`, `q9`, `q10`, `q11`, `q12`, `q13`, `q14`, `q15`, `q16`, `q17`, `q18`, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', img1) AS photo1, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', img2) AS photo2, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', img3) AS photo3, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', img4) AS photo4, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', img5) AS photo5 " + + "FROM guildelines_inspection WHERE isactive = 1 AND cdid = ? AND ciid = ? LIMIT 1"; + List> ansList = jdbcGuidlines.queryForList(ansSql, cdid, ciid); + + Map answers = ansList.isEmpty() ? new HashMap<>() : ansList.get(0); + + // Merge each guideline with its corresponding answer + List> guidelineWithAnswers = new ArrayList<>(); + for (int i = 1; i <= guidelineList.size(); i++) { + Map guideline = guidelineList.get(i - 1); + String qKey = "q" + i; + Map qa = new LinkedHashMap<>(); + qa.put("question", guideline.get("guideline")); + qa.put("question_type", guideline.get("significance")); + qa.put("answer", answers.getOrDefault(qKey, "")); + guidelineWithAnswers.add(qa); + } + + List> guidelineWithImages = new ArrayList<>(); + Map qa_img = new LinkedHashMap<>(); + qa_img.put("image1", answers.get("photo1")); + qa_img.put("image2", answers.get("photo2")); + qa_img.put("image3", answers.get("photo3")); + qa_img.put("image4", answers.get("photo4")); + qa_img.put("image5", answers.get("photo5")); + guidelineWithImages.add(qa_img); + + // attach to response + row.put("guidelines_id", answers.get("giid")); + row.put("guidelines_images", guidelineWithImages); + row.put("guidelines_answers", guidelineWithAnswers); + } + + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "Construction List with Guidelines & Answers."); + response.put("data", result); + + return Collections.singletonList(response); + } + + @Transactional + public List> saveAfterNoticeDetails( + String cdid, + String ciid, + String giid, + String remarks, + String status, + String zone, + String ward, + String cby, + String latitude, + String longitude, + MultipartFile mainfile + ) { + Map response = new HashMap<>(); + List> result = new ArrayList<>(); + + String constimg = fileUpload("After_Notice",cdid+"_"+ciid+"_"+giid+"_"+status , mainfile); + + String type = ""; + + // Prepare question image uploads + MultipartFile[] files = { + mainfile + }; + + // Insert query + String insertSql = "INSERT INTO `after_notice_inspection`(`cdid`, `ciid`, `giid`, `image1`, `remarks`, `zone`, `ward`, `latitude`, `longitude`, `cby`, `status`) VALUES " + + "(?,?,?,?,?,?,?,?,?,?,?)"; + + KeyHolder keyHolder = new GeneratedKeyHolder(); + + int affectedRows = jdbcGuidlines.update(connection -> { + PreparedStatement ps = connection.prepareStatement(insertSql, new String[]{"cdid"}); + int i = 1; + ps.setString(i++, cdid); + ps.setString(i++, ciid); + ps.setString(i++, giid); + ps.setString(i++, constimg); + ps.setString(i++, remarks); + ps.setString(i++, zone); + ps.setString(i++, ward); + ps.setString(i++, latitude); + ps.setString(i++, longitude); + ps.setString(i++, cby); + ps.setString(i++, status); + return ps; + }, keyHolder); + + if (affectedRows > 0) { + int lastInsertId = keyHolder.getKey().intValue(); + response.put("insertId", lastInsertId); + response.put("status", "success"); + response.put("message", "New After Notice details inserted successfully."); + } else { + response.put("status", "error"); + response.put("message", "New After Notice details insert failed."); + } + + result.add(response); + return result; + } + + public List> get7thRevisitConstructionList(String loginid, String latitude, String longitude) { + String sql = "SELECT cd.*, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', cd.image) AS photo, " + + "ci.ciid, ci.under_guidelines, ci.penalty " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', ani.image1) AS finephoto, " + + "date_format(ani.cdate, '%d-%m-%Y') as Fine Date, " + + "ani.cdate as finedate " + + "FROM construction_details cd " + + "LEFT JOIN construction_inspection ci ON ci.cdid = cd.cdid " + + "LEFT JOIN after_notice_inspection ani ON ani.cdid = cd.cdid " + + "WHERE cd.isactive = 1 AND ci.isactive = 1 AND ci.penalty IN ('High','Medium','Low')"; + + List> result = jdbcGuidlines.queryForList(sql); + + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + LocalDate today = LocalDate.now(); + + for (Map row : result) { + Boolean allowRevisit = false; + Object cdateObj = row.get("finedate"); + + if (cdateObj != null) { + System.err.println("Raw cdate type: " + cdateObj.getClass().getName() + " | value: " + cdateObj); + } + + if (cdateObj != null) { + LocalDate cdate = null; + + if (cdateObj instanceof LocalDate) { + cdate = (LocalDate) cdateObj; + } else if (cdateObj instanceof java.sql.Date) { + cdate = ((java.sql.Date) cdateObj).toLocalDate(); + } else if (cdateObj instanceof java.sql.Timestamp) { + cdate = ((java.sql.Timestamp) cdateObj).toLocalDateTime().toLocalDate(); + } else if (cdateObj instanceof LocalDateTime) { + cdate = ((LocalDateTime) cdateObj).toLocalDate(); // ✅ FIX + } else if (cdateObj instanceof String) { + try { + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + cdate = LocalDateTime.parse((String) cdateObj, dtf).toLocalDate(); + } catch (Exception e) { + System.err.println("❌ Could not parse cdate: " + cdateObj); + } + } + + if (cdate != null) { + LocalDate finalDate = cdate.plusDays(7); + allowRevisit = !today.isBefore(finalDate); // true if today >= finalDate + + System.err.println("ID: " + row.get("cdid") + + " | finalDate: " + finalDate + + " | today: " + today + + " | allowRevisit: " + allowRevisit); + /* + if (finalDate.isBefore(today) || finalDate.isEqual(today)) { + allowRevisit = true; + } + */ + } + } + + row.put("allowRevisit", allowRevisit); + + String downloadLink = "https://gccservices.in/gccofficialapp/api/pdf/template?" + + "cdid=" + row.get("cdid") + + "&ciid=" + row.get("ciid"); + + row.put("downloadNoticeLink", downloadLink); + } + + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "Construction List with Guidelines & Answers."); + response.put("data", result); + + return Collections.singletonList(response); + } + + @Transactional + public List> saveFinalNoticeDetails( + String cdid, + String ciid, + String giid, + String remarks, + String status, + String zone, + String ward, + String cby, + String latitude, + String longitude, + MultipartFile mainfile + ) { + Map response = new HashMap<>(); + List> result = new ArrayList<>(); + + String constimg = fileUpload("Final_Notice",cdid+"_"+ciid+"_"+giid+"_"+status , mainfile); + + String type = ""; + + // Prepare question image uploads + MultipartFile[] files = { + mainfile + }; + + // Insert query + String insertSql = "INSERT INTO `final_notice_inspection`(`cdid`, `ciid`, `giid`, `image1`, `remarks`, `zone`, `ward`, `latitude`, `longitude`, `cby`, `status`) VALUES " + + "(?,?,?,?,?,?,?,?,?,?,?)"; + + KeyHolder keyHolder = new GeneratedKeyHolder(); + + int affectedRows = jdbcGuidlines.update(connection -> { + PreparedStatement ps = connection.prepareStatement(insertSql, new String[]{"cdid"}); + int i = 1; + ps.setString(i++, cdid); + ps.setString(i++, ciid); + ps.setString(i++, giid); + ps.setString(i++, constimg); + ps.setString(i++, remarks); + ps.setString(i++, zone); + ps.setString(i++, ward); + ps.setString(i++, latitude); + ps.setString(i++, longitude); + ps.setString(i++, cby); + ps.setString(i++, status); + return ps; + }, keyHolder); + + if (affectedRows > 0) { + int lastInsertId = keyHolder.getKey().intValue(); + response.put("insertId", lastInsertId); + response.put("status", "success"); + response.put("message", "New Final Notice details inserted successfully."); + } else { + response.put("status", "error"); + response.put("message", "New Final Notice details insert failed."); + } + + result.add(response); + return result; + } + + public Map getNoticeData(String cdidtxt, String ciidtxt) { + + String sql = "SELECT cd.*, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', cd.image) AS photo, " + + "DATE_FORMAT(cd.cdate, '%d-%m-%Y') AS ddate, " + + "ci.ciid, ci.under_guidelines, ci.penalty " + + "FROM construction_details cd " + + "LEFT JOIN construction_inspection ci ON ci.cdid = cd.cdid " + + "WHERE cd.isactive = 1 AND ci.isactive = 1 AND ci.penalty IN ('High','Medium','Low') AND cd.cdid=? AND ci.ciid=?"; + + List> result = jdbcGuidlines.queryForList(sql, cdidtxt, ciidtxt); + + Map data = new HashMap<>(); + + // Fetch master guideline list only once + String guidelinesSql = "SELECT `gid`, `guideline`, `significance`, `orderby`, `isactive` FROM guidelines WHERE isactive = 1 ORDER BY orderby"; + List> guidelineList = jdbcGuidlines.queryForList(guidelinesSql); + + for (Map row : result) { + Object cdid = row.get("cdid"); + Object ciid = row.get("ciid"); + + // Fetch answer row for this cdid + ciid + String ansSql = "SELECT `giid`, `cdate`, `q1`, `q2`, `q3`, `q4`, `q5`, `q6`, `q7`, `q8`, `q9`, `q10`, `q11`, `q12`, `q13`, `q14`, `q15`, `q16`, `q17`, `q18`, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', img1) AS photo1, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', img2) AS photo2, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', img3) AS photo3, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', img4) AS photo4, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', img5) AS photo5 " + + "FROM guildelines_inspection WHERE isactive = 1 AND cdid = ? AND ciid = ? LIMIT 1"; + List> ansList = jdbcGuidlines.queryForList(ansSql, cdid, ciid); + + Map answers = ansList.isEmpty() ? new HashMap<>() : ansList.get(0); + + // Merge each guideline with its corresponding answer + List> guidelineWithAnswers = new ArrayList<>(); + List clauseList = new ArrayList<>(); + List> violations = new ArrayList<>(); + for (int i = 1; i <= guidelineList.size(); i++) { + Map guideline = guidelineList.get(i - 1); + String qKey = "q" + i; + Map qa = new LinkedHashMap<>(); + String ans = String.valueOf(answers.get(qKey)); + if("No".equalsIgnoreCase(ans)) { + Map v = new HashMap<>(); + v.put("message", guideline.get("guideline")); // You can also include clause if needed + violations.add(v); + clauseList.add(i); + } + } + + String buildupAreaStr = row.get("buildup_area").toString(); + int buildup_area = Integer.parseInt(buildupAreaStr); + + System.out.println("buildup_area : "+buildup_area); + + String penaltyCategory = row.get("penalty").toString(); // should be "High" or "Low" + + System.out.println("penaltyCategory : "+penaltyCategory); + + int fineAmount = 0; + + if (buildup_area > 20000) { + if ("High".equalsIgnoreCase(penaltyCategory)) { + fineAmount = 500000; + } else { + fineAmount = 100000; + } + } else if (buildup_area > 500) { + if ("High".equalsIgnoreCase(penaltyCategory)) { + fineAmount = 25000; + } else { + fineAmount = 10000; + } + } else if (buildup_area >= 300 && buildup_area <= 500) { + if ("High".equalsIgnoreCase(penaltyCategory)) { + fineAmount = 10000; + } else { + fineAmount = 1000; + } + } + System.out.println("fineAmount : "+fineAmount); + + data.put("siteLocation", row.get("site_address")); + data.put("violations", violations); + data.put("violationLevel", row.get("penalty")); + data.put("clause", clauseList); + data.put("fineAmount", fineAmount); + data.put("fineAmountWords", convertNumberToIndianWords(fineAmount)); + data.put("date", row.get("ddate")); + } + return data; + } + + public static String convertNumberToIndianWords(long number) { + if (number == 0) return "Zero"; + + final String[] units = { "", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", + "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", + "Seventeen", "Eighteen", "Nineteen" }; + + final String[] tens = { "", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety" }; + + final String[] places = { "", "Thousand", "Lakh", "Crore" }; + + StringBuilder words = new StringBuilder(); + + int[] parts = new int[4]; + parts[0] = (int) (number % 1000); // hundreds + parts[1] = (int) ((number / 1000) % 100); // thousands + parts[2] = (int) ((number / 100000) % 100); // lakhs + parts[3] = (int) (number / 10000000); // crores + + for (int i = 3; i >= 0; i--) { + if (parts[i] != 0) { + if (parts[i] < 20) { + words.append(units[parts[i]]); + } else { + words.append(tens[parts[i] / 10]); + if ((parts[i] % 10) != 0) { + words.append(" ").append(units[parts[i] % 10]); + } + } + words.append(" ").append(places[i]).append(" "); + } + } + + if (parts[0] > 0) { + int h = parts[0] / 100; + int rem = parts[0] % 100; + if (h > 0) { + words.append(units[h]).append(" Hundred "); + } + if (rem > 0) { + if (rem < 20) { + words.append(units[rem]); + } else { + words.append(tens[rem / 10]); + if ((rem % 10) != 0) { + words.append(" ").append(units[rem % 10]); + } + } + } + } + + return words.toString().trim(); + } +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/constructionGuidelines/service/package-info.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/constructionGuidelines/service/package-info.java new file mode 100644 index 0000000..7122dee --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/constructionGuidelines/service/package-info.java @@ -0,0 +1 @@ +package in.gov.chennaicorporation.mobileservice.constructionGuidelines.service; \ No newline at end of file diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/controller/APIOfficialController.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/controller/APIOfficialController.java index 3cfe2d6..31e2040 100644 --- a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/controller/APIOfficialController.java +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/controller/APIOfficialController.java @@ -44,9 +44,10 @@ public class APIOfficialController { @GetMapping(value="/sendOTP") public List sendOTP(HttpServletRequest request, @RequestParam("mobileNo") String mobileNo, - @RequestParam("otpLength") Integer OTP_LENGTH) { + @RequestParam("otpLength") Integer OTP_LENGTH, + @RequestParam(value = "mobilenocheck", required = false) String checkmobileno) { String generatedToken = OTPGenerator.generateOTP(OTP_LENGTH); - return officialAPIService.sendOTP(request, mobileNo, generatedToken); + return officialAPIService.sendOTP(request, mobileNo, generatedToken, checkmobileno); } @PostMapping(value="/savePassword") public List savePetition( diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/controller/PdfTemplateController.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/controller/PdfTemplateController.java new file mode 100644 index 0000000..c3305d7 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/controller/PdfTemplateController.java @@ -0,0 +1,75 @@ +package in.gov.chennaicorporation.mobileservice.controller; + +import java.time.LocalDate; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import in.gov.chennaicorporation.mobileservice.constructionGuidelines.service.GuidelinesService; +import in.gov.chennaicorporation.mobileservice.service.PdfGeneratorService; + +@RestController +@RequestMapping("/gccofficialapp/api/pdf") +public class PdfTemplateController { + + @Autowired + private PdfGeneratorService pdfGeneratorService; + + @Autowired + private GuidelinesService guidelinesService; +/* + @GetMapping("/template") + public ResponseEntity generateFromTemplate( + @RequestParam(value = "cdid", required = false) String cdid, + @RequestParam(value = "ciid", required = false) String ciid + ) { + //Map data = new HashMap<>(); + + //data.put("siteLocation", siteLocation); + //data.put("violations", violations); + //data.put("violationLevel", violationLevel); + //data.put("clause", clause); + //data.put("fineAmount", fineAmount); + //data.put("date", LocalDate.now().toString()); + + + String attachmentFileName="UNDER_CLEAN_AND_SAFE_CONSTRUCTION_GUIDELINES_NOTICE_"+LocalDate.now().toString()+"pdf"; + + byte[] pdfBytes = pdfGeneratorService.generatePdf(guidelinesService.getNoticeData(cdid, ciid)); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_PDF); + headers.setContentDispositionFormData("attachment", attachmentFileName); + + return new ResponseEntity<>(pdfBytes, headers, HttpStatus.OK); + } + */ + @GetMapping("/template") + public ResponseEntity generateFromTemplate( + @RequestParam(value = "cdid", required = false) String cdid, + @RequestParam(value = "ciid", required = false) String ciid + ) { + String attachmentFileName = "UNDER_CLEAN_AND_SAFE_CONSTRUCTION_GUIDELINES_NOTICE_" + LocalDate.now() + ".pdf"; + + // Generate PDF content + byte[] pdfBytes = pdfGeneratorService.generatePdf( + guidelinesService.getNoticeData(cdid, ciid) + ); + + // Prepare response headers + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_PDF); + headers.setContentDispositionFormData("attachment", attachmentFileName); + + return new ResponseEntity<>(pdfBytes, headers, HttpStatus.OK); + } +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/erpPostData/erppostdataController.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/erpPostData/erppostdataController.java new file mode 100644 index 0000000..1b79da7 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/erpPostData/erppostdataController.java @@ -0,0 +1,5 @@ +package in.gov.chennaicorporation.mobileservice.erpPostData; + +public class erppostdataController { + +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/erpPostData/erppostdataService.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/erpPostData/erppostdataService.java new file mode 100644 index 0000000..97ad988 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/erpPostData/erppostdataService.java @@ -0,0 +1,191 @@ +package in.gov.chennaicorporation.mobileservice.erpPostData; + +import java.sql.Timestamp; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +import org.springframework.http.*; +import org.springframework.web.client.RestTemplate; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +@Service +public class erppostdataService { + + @Autowired + private JdbcTemplate jdbcTemplate; + + @Autowired + public void setDataSource(@Qualifier("mysqlPenaltyDataSource") DataSource penaltyDataSource) { + this.jdbcTemplate = new JdbcTemplate(penaltyDataSource); + } + // This method runs every 1 hour (3600000 ms) + @Scheduled(fixedRate = 60 * 60 * 1000) + //@Scheduled(cron = "0 0 * * * *") // every hour at 0th minute + public void postDataToERP() { + // Call the logic you currently expose through controller + System.out.println("Posting data to ERP at " + java.time.LocalDateTime.now()); + postPOSToERP(); // FOR PENALTY POS (gcc_penalty_pos) + } + + private String postPOSToERP() { + System.out.println("ERP txn: Started"); + String sql = "SELECT " + + " bt.id, " + + " bt.txnDate, " + + " DATE_FORMAT(bt.txnDate, '%Y') AS TRANSACTIONYEAR, " + + " DATE_FORMAT(bt.txnDate, '%d/%m/%Y') AS TRANSACTIONDATE, " + + " bt.txnId AS TRANSACTIONNO, " + + " bt.transactionAmount AS TOTALTRANSACTIONAMOUNT, " + + " bt.txnRefNo AS TRANSACTIONREFNO, " + + " '450310000' AS TOTALTRANSACTIONCODE, " + + " pcat.erpcode AS MSTRCODEONE, " + + " 0 AS SPLITAMOUNTONE, " + + " pc.violator_name AS PARTYNAME, " + + " pc.violator_company AS PARTYADDRESS, " + + " pc.violator_phone AS PARTYMOBILE, " + + " pc.id AS UNIQUERECEIPTID " + + "FROM " + + " `bank_transactions` bt " + + "LEFT JOIN " + + " `penalty_challan` pc ON bt.txnId = pc.orderid " + + " AND pc.isactive = 1 " + + " AND pc.isdelete = 0 " + + " AND bt.txnMode NOT IN ('Hand cash','Cheque','DD') " + + "LEFT JOIN " + + " `penalty_category` pcat ON pcat.id = pc.category_id " + + "WHERE bt.erp_post_status IS NULL OR bt.erp_post_status != 'posted' " + + " AND bt.erp_post_message != 'Already Updated this collection' " + + "ORDER BY `bt`.`id` ASC"; + try { + + System.out.println("Running ERP sync..."); + System.out.println("Using SQL:\n" + sql); + System.out.println("Connecting to: " + jdbcTemplate.getDataSource().getConnection().getMetaData().getURL()); + + List> result = jdbcTemplate.queryForList(sql); + System.out.println("ERP txt Total records: : "+result.size()); + for (Map row : result) { + String ID = String.valueOf(row.get("id")); + System.out.println("ERP TXT DATA : "+ID); + String ASSESSMENTNO = row.get("TRANSACTIONYEAR")+"/Fine/"+row.get("id"); + String UNIQUERECEIPTID = String.valueOf(row.get("UNIQUERECEIPTID")); + String TRANSACTIONNO = String.valueOf(row.get("TRANSACTIONNO")); + String TRANSACTIONREFNO = String.valueOf(row.get("TRANSACTIONREFNO")); // optional mapping + String TRANSACTIONDATE = String.valueOf(row.get("TRANSACTIONDATE")); + String TOTALTRANSACTIONAMOUNT = String.valueOf(row.get("TOTALTRANSACTIONAMOUNT")); + String TOTALTRANSACTIONCODE = String.valueOf(row.get("TOTALTRANSACTIONCODE")); + String MSTRCODEONE = String.valueOf(row.get("MSTRCODEONE")); + String SPLITAMOUNTONE = String.valueOf(row.get("SPLITAMOUNTONE")); + String PARTYNAME = String.valueOf(row.get("PARTYNAME")); + String PARTYADDRESS = String.valueOf(row.get("PARTYADDRESS")); + String PARTYMOBILE = String.valueOf(row.get("PARTYMOBILE")); + + String response = postToErp( + ID, + ASSESSMENTNO, + UNIQUERECEIPTID, + TRANSACTIONNO, + TRANSACTIONREFNO, + TRANSACTIONDATE, + TOTALTRANSACTIONAMOUNT, + TOTALTRANSACTIONCODE, + MSTRCODEONE, + SPLITAMOUNTONE, + PARTYNAME, + PARTYADDRESS, + PARTYMOBILE + ); + + // ✅ Exit loop immediately if ERP server down or response is not "success" + if ("server_down".equalsIgnoreCase(response)) { + System.out.println("ERP server is down or unreachable. Halting current loop..."); + break; // stop further processing in this cycle + } + + // Optionally log response + System.out.println("ERP Response for txn: " + TRANSACTIONNO + " → " + response); + } + + return "success"; + + } catch (Exception e) { + e.printStackTrace(); + return "erp error: " + e.getMessage(); + } + } + + private String postToErp( + String id, + String ASSESSMENTNO, + String UNIQUERECEIPTID, + String TRANSACTIONNO, + String TRANSACTIONREFNO, + String TRANSACTIONDATE, + String TOTALTRANSACTIONAMOUNT, + String TOTALTRANSACTIONCODE, + String MSTRCODEONE, + String SPLITAMOUNTONE, + String PARTYNAME, + String PARTYADDRESS, + String PARTYMOBILE) { + System.out.println("ERP txn request: ERP"); + String erpURL = "http://coc-staging.egovernments.org:9980/pgr/external/mobileservice?serviceId=getOtherCollection" + + "&COLLECTION_TYPE=Fine Collection" + + "&ASSESSMENTNO=" + ASSESSMENTNO + + "&UNIQUERECEIPTID=" + UNIQUERECEIPTID + + "&TRANSACTIONNO=" + TRANSACTIONNO + + "&TRANSACTIONREFNO=" + TRANSACTIONREFNO + + "&TRANSACTIONDATE=" + TRANSACTIONDATE + + "&TOTALTRANSACTIONAMOUNT=" + TOTALTRANSACTIONAMOUNT + + "&TOTALTRANSACTIONCODE=" + TOTALTRANSACTIONCODE + + "&MSTRCODEONE=" + MSTRCODEONE + + "&SPLITAMOUNTONE=" + SPLITAMOUNTONE + + "&PARTYNAME=" + PARTYNAME + + "&PARTYADDRESS=" + PARTYADDRESS + + "&PARTYMOBILE=" + PARTYMOBILE; + + RestTemplate restTemplate = new RestTemplate(); + System.out.println("ERP URL:" + erpURL); + try { + ResponseEntity response = restTemplate.exchange(erpURL, HttpMethod.GET, null, String.class); + + if (response.getStatusCode() == HttpStatus.OK) { + ObjectMapper mapper = new ObjectMapper(); + JsonNode jsonNode = mapper.readTree(response.getBody()); + + boolean resultStatus = jsonNode.path("ResultStatus").asBoolean(); // this is already a boolean + String message = jsonNode.path("Message").asText(); // capture the message string + + if (resultStatus) { + String updateSql = "UPDATE bank_transactions SET erp_post_status = 'posted', erp_post_message = ?, erp_post_date = ? WHERE id = ?"; + jdbcTemplate.update(updateSql, message, Timestamp.valueOf(LocalDateTime.now()), id); + } else { + String updateSql = "UPDATE bank_transactions SET erp_post_status = 'failed', erp_post_message = ?, erp_post_date = ? WHERE id = ?"; + jdbcTemplate.update(updateSql, message, Timestamp.valueOf(LocalDateTime.now()), id); + } + + return resultStatus ? "success" : "failed"; + + } else { + return "failed"; // Non-200 response from server + } + + } catch (Exception ex) { + System.out.println("Error contacting ERP server: " + ex.getMessage()); + return "server_down"; + } + } +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/erpPostData/package-info.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/erpPostData/package-info.java new file mode 100644 index 0000000..2360ef3 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/erpPostData/package-info.java @@ -0,0 +1 @@ +package in.gov.chennaicorporation.mobileservice.erpPostData; \ No newline at end of file diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccDomesticWaste/Controller/DomesticWasteController.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccDomesticWaste/Controller/DomesticWasteController.java new file mode 100644 index 0000000..b932d83 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccDomesticWaste/Controller/DomesticWasteController.java @@ -0,0 +1,145 @@ +package in.gov.chennaicorporation.mobileservice.gccDomesticWaste.Controller; +import in.gov.chennaicorporation.mobileservice.gccDomesticWaste.Service.DomesticWasteService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("/gccofficialapp/api/domesticwaste") +public class DomesticWasteController { + + @Autowired + DomesticWasteService domesticWasteService; + + + + @PostMapping("/save-request") + public ResponseEntity saveRequest( + @RequestParam String user_name, + @RequestParam String mobile, + @RequestParam String address, + @RequestParam String latitude, + @RequestParam String longitude, + @RequestParam String zone, + @RequestParam String division, + @RequestParam String street_name, + @RequestParam String street_id, + @RequestParam String remarks, + @RequestParam("items") String itemsJson, + @RequestParam (name = "image") MultipartFile imageFile) { + + try { + Map result = domesticWasteService.saveMultipleWasteRequests( + user_name, mobile, address, + latitude, longitude, zone, division, + street_name, street_id, remarks, + imageFile, itemsJson + ); + + return ResponseEntity.ok(result); + + } catch (Exception e) { + return ResponseEntity.status(500).body(Map.of("status", false, "message", e.getMessage())); + } + } + + + @GetMapping("/get-all-requests") + public ResponseEntity>> getAllWasteRequests() { + List> results = domesticWasteService.getAllWasteRequests(); + return ResponseEntity.ok(results); + } + + @GetMapping("/get-all-requests-by-login") + public ResponseEntity>> getAllWasteRequests(@RequestParam String loginId) { + List> results = domesticWasteService.getAllWasteRequestsbylogin(loginId); + return ResponseEntity.ok(results); + } + + @GetMapping("/get-all-masters") + public ResponseEntity>> getAllmasters() { + List> results = domesticWasteService.getAllmasters(); + return ResponseEntity.ok(results); + } + + @GetMapping("/get-user-bymobile") + public ResponseEntity>> getuserbymobile(@RequestParam String mobile) { + List> results =domesticWasteService.getuserbymobile(mobile); + return ResponseEntity.ok(results); + } + + @GetMapping("/get-user-AE2") + public ResponseEntity>> getUserAE2(@RequestParam String loginId) { + List> results = domesticWasteService.getuserAE2(loginId); + return ResponseEntity.ok(results); + } + + // Zonal Requests based on loginId + @GetMapping("/get-user-zonal") + public ResponseEntity>> getUserZonal(@RequestParam String loginId) { + List> results = domesticWasteService.getuserZonal(loginId); + return ResponseEntity.ok(results); + } + + @GetMapping("/userdetailsfilter") + public ResponseEntity>> userdetailsfilter(@RequestParam int id) { + List> results =domesticWasteService.userdetailsfilter(id); + return ResponseEntity.ok(results); + } + + @PostMapping("/action-taken") + public ResponseEntity saveActionTaken( + @RequestParam int reqid, + @RequestParam(value = "image") MultipartFile image, + @RequestParam("created_by") int createdBy, + @RequestParam String latitude, + @RequestParam String longitude + ) { + Map result = domesticWasteService.actionTaken(String.valueOf(reqid), image, createdBy,latitude,longitude); + + if ((boolean) result.get("status")) { + return ResponseEntity.ok(result); + } else { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result); + } + } + + @PostMapping("/reject-user-req") + public ResponseEntity rejectuserreq(@RequestParam String requestId) { + Map result = domesticWasteService.rejectuserreq(requestId); + return ResponseEntity.ok(result); + } + + @GetMapping("/verify-latlong") + public ResponseEntity> verifyLatLong( + @RequestParam String requestId, + @RequestParam String latitude, + @RequestParam String longitude) { + + boolean result = domesticWasteService.verifylatlong(requestId, latitude, longitude); + + Map response = Map.of( + "status", true, + "message", String.valueOf(result) + ); + + return ResponseEntity.ok(response); + } + + @PostMapping("/reject-request-officer") + public ResponseEntity> rejectUserRequestByOfficer( + @RequestParam String requestId, + @RequestParam String officer_remark, + @RequestParam String rejecttype, + @RequestParam int cancelled_by, + @RequestParam String latitude, + @RequestParam String longitude) { + + Map result = domesticWasteService.rejectuserreqofficer(requestId, officer_remark, rejecttype, cancelled_by,latitude,longitude); + return ResponseEntity.ok(result); + } +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccDomesticWaste/Scheduler/DomesticWasteScheduler.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccDomesticWaste/Scheduler/DomesticWasteScheduler.java new file mode 100644 index 0000000..2f1606b --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccDomesticWaste/Scheduler/DomesticWasteScheduler.java @@ -0,0 +1,28 @@ +package in.gov.chennaicorporation.mobileservice.gccDomesticWaste.Scheduler; + +import in.gov.chennaicorporation.mobileservice.gccDomesticWaste.Service.DomesticWasteService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Component +@EnableScheduling +public class DomesticWasteScheduler { + @Autowired + private DomesticWasteService domesticWasteService; + + + @Scheduled(cron = "0 0 1 * * WED", zone = "Asia/Kolkata") + //@Scheduled(fixedRate = 3000) + public void domesticWasteScheduler() { + System.out.println("DomesticWasteScheduler Started......"); + Map result= domesticWasteService.updateOrderStatus("3"); + System.out.println("Scheduler Result: " + result); + + } + + +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccDomesticWaste/Service/DomesticWasteService.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccDomesticWaste/Service/DomesticWasteService.java new file mode 100644 index 0000000..982cbd3 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccDomesticWaste/Service/DomesticWasteService.java @@ -0,0 +1,631 @@ +package in.gov.chennaicorporation.mobileservice.gccDomesticWaste.Service; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.core.env.Environment; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; +import java.io.File; +import java.io.IOException; +import java.sql.PreparedStatement; +import java.sql.Statement; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import javax.sql.DataSource; + +@Service +public class DomesticWasteService { + + @Autowired + + private JdbcTemplate jdbcDomesticWasteTemplate; + + @Value("${file.upload.directory}") + private String baseUploadDir; + + @Value("${domestic_waste_foldername}") + private String wasteFolder; + + + private String fileBaseUrl; + + @Autowired + private Environment environment; + + @Autowired + public void setDataSource(@Qualifier("mysqlGccDomesticWasteManagementDataSource") DataSource DomesticWasteManagementDataSource) { + this.jdbcDomesticWasteTemplate = new JdbcTemplate(DomesticWasteManagementDataSource); + } + + + + public DomesticWasteService(Environment environment) { + this.environment = environment; + this.fileBaseUrl = environment.getProperty("fileBaseUrl"); + } + + + public String fileUpload(MultipartFile file, String prefix) { + if (file == null || file.isEmpty()) { + return null; + } + + try { + String year = String.valueOf(LocalDate.now().getYear()); + String month = String.format("%02d", LocalDate.now().getMonthValue()); + String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("ddMMyyyyHHmmss")); + + // Clean original file name + String originalFilename = file.getOriginalFilename().replaceAll("\\s+", ""); + String fileName = prefix + "_" + timestamp + "_" + originalFilename; + + // Create upload directory path + String uploadDirPath = baseUploadDir + wasteFolder + year + "/" + month; + File uploadDir = new File(uploadDirPath); + if (!uploadDir.exists()) { + uploadDir.mkdirs(); + } + + // Save file to server + File fullFilePath = new File(uploadDirPath + File.separator + fileName); + file.transferTo(fullFilePath); + + // Return relative path to save in DB + return "/" + wasteFolder + year + "/" + month + "/" + fileName; + + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + public Map saveMultipleWasteRequests(String user_name, String mobile, String address, + String latitude, String longitude, String zone, String division, + String street_name, String street_id, String remarks, + MultipartFile imageFile, String itemsJson) { + + String imagePath = fileUpload(imageFile, "domestic_waste_photo"); + if (imagePath == null) { + return Map.of("status", false, "message", "Image upload failed"); + } + + try { + // Step 1: Insert main request (one time) + String insertMainSql = "INSERT INTO user_request_table " + + "(request_id, user_name, mobile, address, latitude, longitude, zone, division, street_name, street_id, remarks, image_url) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + KeyHolder keyHolder = new GeneratedKeyHolder(); + jdbcDomesticWasteTemplate.update(con -> { + PreparedStatement ps = con.prepareStatement(insertMainSql, Statement.RETURN_GENERATED_KEYS); + ps.setString(1, "TEMP"); // placeholder + ps.setString(2, user_name); + ps.setString(3, mobile); + ps.setString(4, address); + ps.setString(5, latitude); + ps.setString(6, longitude); + ps.setString(7, zone); + ps.setString(8, division); + ps.setString(9, street_name); + ps.setString(10, street_id); + ps.setString(11, remarks); + ps.setString(12, imagePath); + return ps; + }, keyHolder); + + int generatedId = keyHolder.getKey().intValue(); + String requestId = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + generatedId; + + // Update request_id in user_request_table + jdbcDomesticWasteTemplate.update("UPDATE user_request_table SET request_id = ? WHERE id = ?", requestId, generatedId); + + // Step 2: Insert items under the same request_id into the `items` table + ObjectMapper objectMapper = new ObjectMapper(); + List> items = objectMapper.readValue(itemsJson, new TypeReference<>() {}); + + String insertItemSql = "INSERT INTO items (iteam_id, quantity, req_table_id, requedt_id) VALUES (?, ?, ?, ?)"; + + for (Map item : items) { + Object itemIdObj = item.get("item_id"); + Object quantityObj = item.get("quantity"); + + if (itemIdObj == null || quantityObj == null) { + continue; + } + + int itemId = Integer.parseInt(itemIdObj.toString()); + int quantity = Integer.parseInt(quantityObj.toString()); + + jdbcDomesticWasteTemplate.update(insertItemSql, itemId, quantity, generatedId, requestId); + } + + return Map.of( + "status", true, + "message", "Request saved successfully", + "requestId", requestId + ); + + } catch (Exception e) { + e.printStackTrace(); + return Map.of("status", false, "message", "Error: " + e.getMessage()); + } + } + + public List> getAllWasteRequests() { + /*String sql = "SELECT " + + "u.id, u.request_id, u.user_name, u.mobile, u.address, u.latitude, u.longitude, " + + "u.zone, u.division, u.street_name, u.street_id, u.quantity, u.remarks, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', u.image_url) AS image_url, " + + "itm.quantity, i.item_name " + + "FROM user_request_table u " + + "LEFT JOIN items itm ON u.id = itm.req_table_id " + + "LEFT JOIN item_master i ON itm.iteam_id = i.id AND i.is_active = 1"; + */ + String sql = "SELECT " + + "u.*, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', u.image_url) AS image_full_url, " + + "itm.quantity, i.item_name " + + "FROM user_request_table u " + + "LEFT JOIN items itm ON u.id = itm.req_table_id " + + "LEFT JOIN item_master i ON itm.iteam_id = i.id AND i.is_active = 1"; + + List> rawData = jdbcDomesticWasteTemplate.queryForList(sql); + return groupRequestsWithItems(rawData); + } + + public List> getAllWasteRequestsbylogin(String loginId) { + String zoneSql = "SELECT zone, division FROM officer_master WHERE loginId = ? AND is_active = 1 AND is_delete = 0"; + List> zoneList = jdbcDomesticWasteTemplate.queryForList(zoneSql, loginId); + + //if (zoneList.isEmpty()) return List.of(); + if (zoneList.isEmpty()) { + Map response = new HashMap<>(); + response.put("status", false); + response.put("message", "No data found"); + return Collections.singletonList(response); // or just `response` depending on your return type + } + + List params = new ArrayList<>(); + StringBuilder zoneCondition = new StringBuilder("("); + + for (int i = 0; i < zoneList.size(); i++) { + Map row = zoneList.get(i); + zoneCondition.append("(u.zone = ? AND u.division = ?)"); + if (i < zoneList.size() - 1) zoneCondition.append(" OR "); + params.add(row.get("zone")); + params.add(row.get("division")); + } + zoneCondition.append(") ORDER BY u.cdate DESC"); + /* + String sql = "SELECT " + + "u.*, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', u.image_url) AS image_full_url, " + + "itm.quantity, i.item_name " + + "FROM user_request_table u " + + "LEFT JOIN items itm ON u.id = itm.req_table_id " + + "LEFT JOIN item_master i ON itm.iteam_id = i.id AND i.is_active = 1"; + */ + String sql = "SELECT " + + "u.id, u.request_id, u.user_name, u.mobile, u.address, u.latitude, u.longitude, " + + "u.zone, u.division, u.street_name, u.quantity AS main_quantity, u.remarks, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', u.image_url) AS image_url, " + + "DATE_FORMAT(u.cdate, '%d-%m-%Y') AS cdate, " + + "u.is_active, u.is_delete, u.street_id, sm.status_master AS status, u.is_app, " + + "DATE_FORMAT(u.close_date, '%d-%m-%Y') AS close_date, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', u.officer_upload_url) AS officer_upload_url, " + + "itm.quantity, im.item_name " + + "FROM user_request_table u " + + "LEFT JOIN items itm ON u.id = itm.req_table_id " + + "LEFT JOIN item_master im ON itm.iteam_id = im.id AND im.is_active = 1 " + + "LEFT JOIN status_master sm ON sm.id = u.status AND sm.is_active = 1 AND sm.is_delete = 0 " + + "WHERE u.status IN(1,3) " + + "AND u.is_active = 1 AND " + zoneCondition; + + List> rawData = jdbcDomesticWasteTemplate.queryForList(sql, params.toArray()); + return groupRequestsWithItems(rawData); + } + + public List> getAllmasters() { + String sql = "select id,item_name from item_master where is_active= 1"; + return jdbcDomesticWasteTemplate.queryForList(sql); + } + + public List> getuserbymobile(String mobile) { + String sql = "SELECT " + + "u.id, u.request_id, u.user_name, u.mobile, u.address, u.latitude, u.longitude, " + + "u.zone, u.division, u.street_name, u.quantity AS main_quantity, u.remarks, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', u.image_url) AS image_url, " + + "DATE_FORMAT(u.cdate, '%d-%m-%Y') AS cdate, " + + "u.is_active, u.is_delete, u.street_id, sm.status_master AS status, u.is_app, " + + "DATE_FORMAT(u.close_date, '%d-%m-%Y') AS close_date, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', u.officer_upload_url) AS officer_upload_url, " + + "itm.iteam_id, itm.quantity, im.item_name " + + "FROM user_request_table u " + + "LEFT JOIN items itm ON u.id = itm.req_table_id " + + "LEFT JOIN item_master im ON itm.iteam_id = im.id AND im.is_active = 1 " + + "LEFT JOIN status_master sm ON sm.id = u.status AND sm.is_active = 1 AND sm.is_delete = 0 " + + "WHERE u.mobile = ? AND u.is_active = 1"; + + List> rawList = jdbcDomesticWasteTemplate.queryForList(sql, mobile); + + Map> groupedMap = new LinkedHashMap<>(); + + for (Map row : rawList) { + Integer id = (Integer) row.get("id"); + + Map item = null; + if (row.get("item_name") != null) { + item = new LinkedHashMap<>(); + item.put("item_name", row.get("item_name")); + item.put("quantity", row.get("quantity")); + } + + if (groupedMap.containsKey(id)) { + if (item != null) { + ((List>) groupedMap.get(id).get("items")).add(item); + } + } else { + Map newEntry = new LinkedHashMap<>(); + newEntry.put("id", id); + newEntry.put("request_id", row.get("request_id")); + newEntry.put("user_name", row.get("user_name")); + newEntry.put("mobile", row.get("mobile")); + newEntry.put("address", row.get("address")); + newEntry.put("latitude", row.get("latitude")); + newEntry.put("longitude", row.get("longitude")); + newEntry.put("zone", row.get("zone")); + newEntry.put("division", row.get("division")); + newEntry.put("street_name", row.get("street_name")); + newEntry.put("main_quantity", row.get("main_quantity")); + newEntry.put("remarks", row.get("remarks")); + newEntry.put("image_url", row.get("image_url")); + newEntry.put("cdate", row.get("cdate")); + newEntry.put("is_active", row.get("is_active")); + newEntry.put("is_delete", row.get("is_delete")); + newEntry.put("street_id", row.get("street_id")); + newEntry.put("status", row.get("status")); // Now this is human-readable + newEntry.put("is_app", row.get("is_app")); + newEntry.put("close_date", row.get("close_date")); + newEntry.put("officer_upload_url", row.get("officer_upload_url")); + + List> items = new ArrayList<>(); + if (item != null) { + items.add(item); + } + newEntry.put("items", items); + + groupedMap.put(id, newEntry); + } + } + + return new ArrayList<>(groupedMap.values()); + } + + public List> getuserAE2(String loginId) { + String zoneSql = "SELECT zone, division FROM officer_master WHERE loginId = ? AND is_active = 1 AND is_delete = 0"; + List> zoneList = jdbcDomesticWasteTemplate.queryForList(zoneSql, loginId); + + //if (zoneList.isEmpty()) return List.of(); + if (zoneList.isEmpty()) { + Map response = new HashMap<>(); + response.put("status", false); + response.put("message", "No data found"); + return Collections.singletonList(response); // or just `response` depending on your return type + } + + List params = new ArrayList<>(); + StringBuilder zoneCondition = new StringBuilder("("); + + for (int i = 0; i < zoneList.size(); i++) { + Map row = zoneList.get(i); + zoneCondition.append("(u.zone = ? AND u.division = ?)"); + if (i < zoneList.size() - 1) zoneCondition.append(" OR "); + params.add(row.get("zone")); + params.add(row.get("division")); + } + zoneCondition.append(")"); + + String sql = "SELECT " + + "u.id, u.request_id, u.user_name, u.mobile, u.address, u.latitude, u.longitude, " + + "u.zone, u.division, u.street_name, u.quantity AS main_quantity, u.remarks, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', u.image_url) AS image_url, " + + "DATE_FORMAT(u.cdate, '%d-%m-%Y') AS cdate, " + + "u.is_active, u.is_delete, u.street_id, sm.status_master AS status, u.is_app, " + + "DATE_FORMAT(u.close_date, '%d-%m-%Y') AS close_date, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', u.officer_upload_url) AS officer_upload_url, " + + "itm.quantity, im.item_name " + + "FROM user_request_table u " + + "LEFT JOIN items itm ON u.id = itm.req_table_id " + + "LEFT JOIN item_master im ON itm.iteam_id = im.id AND im.is_active = 1 " + + "LEFT JOIN status_master sm ON sm.id = u.status AND sm.is_active = 1 AND sm.is_delete = 0 " + + "WHERE u.status != '2' " + + "AND u.cdate <= ( CURDATE() - INTERVAL ((WEEKDAY(CURDATE()) + 5) % 7) DAY ) " + + "AND u.is_active = 1 AND " + zoneCondition; + + List> rawData = jdbcDomesticWasteTemplate.queryForList(sql, params.toArray()); + return groupRequestsWithItems(rawData); + } + + + public List> getuserZonal(String loginId) { + String zoneSql = "SELECT zone, division FROM officer_master WHERE loginId = ? AND is_active = 1 AND is_delete = 0"; + List> zoneList = jdbcDomesticWasteTemplate.queryForList(zoneSql, loginId); + + //if (zoneList.isEmpty()) return List.of(); + if (zoneList.isEmpty()) { + Map response = new HashMap<>(); + response.put("status", false); + response.put("message", "No data found"); + return Collections.singletonList(response); // or just `response` depending on your return type + } + + List params = new ArrayList<>(); + StringBuilder zoneCondition = new StringBuilder("("); + + for (int i = 0; i < zoneList.size(); i++) { + Map row = zoneList.get(i); + zoneCondition.append("(u.zone = ? AND u.division = ?)"); + if (i < zoneList.size() - 1) zoneCondition.append(" OR "); + params.add(row.get("zone")); + params.add(row.get("division")); + } + zoneCondition.append(")"); + + String sql = "SELECT " + + "u.id, u.request_id, u.user_name, u.mobile, u.address, u.latitude, u.longitude, " + + "u.zone, u.division, u.street_name, u.remarks, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', u.image_url) AS image_url, " + + "DATE_FORMAT(u.cdate, '%d-%m-%Y') AS cdate, " + + "u.is_active, u.is_delete, u.street_id, sm.status_master AS status, u.is_app, " + + "DATE_FORMAT(u.close_date, '%d-%m-%Y') AS close_date, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', u.officer_upload_url) AS officer_upload_url, " + + "itm.quantity, im.item_name " + + "FROM user_request_table u " + + "LEFT JOIN items itm ON u.id = itm.req_table_id " + + "LEFT JOIN item_master im ON itm.iteam_id = im.id AND im.is_active = 1 " + + "LEFT JOIN status_master sm ON sm.id = u.status AND sm.is_active = 1 AND sm.is_delete = 0 " + + "WHERE u.status != '2' " + + "AND u.cdate <= ( CURDATE() - INTERVAL ((WEEKDAY(CURDATE()) + 4) % 7) DAY ) " + + "AND u.is_active = 1 AND " + zoneCondition; + + List> rawData = jdbcDomesticWasteTemplate.queryForList(sql, params.toArray()); + return groupRequestsWithItems(rawData); + } + + + public List> userdetailsfilter(int id) { + String fileBaseUrl = environment.getProperty("fileBaseUrl"); + + // Step 1: Fetch zone, division, and street_id for the given request ID + String sql = "SELECT zone, division, street_id FROM user_request_table WHERE id = ?"; + List> result = jdbcDomesticWasteTemplate.queryForList(sql, id); + + if (result.isEmpty()) { + Map response = new HashMap<>(); + response.put("status", false); + response.put("message", "No data found"); + return Collections.singletonList(response); // or just `response` depending on your return type + } + + Map user = result.get(0); + String zone = (String) user.get("zone"); + String division = (String) user.get("division"); + Object streetIdObj = user.get("street_id"); + + // Step 2: Construct dynamic SQL query with/without street_id + String finalSql; + List params = new ArrayList<>(); + params.add(zone); + params.add(division); + + if (streetIdObj != null && !streetIdObj.toString().isBlank()) { + params.add(streetIdObj); + params.add(id); + finalSql = "SELECT u.id, u.request_id, u.user_name, u.mobile, u.address, u.latitude, u.longitude, " + + "u.zone, u.division, u.street_name, u.remarks, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', u.image_url) AS image_url, " + + "DATE_FORMAT(u.cdate, '%d-%m-%Y') AS cdate, u.is_active, u.is_delete, u.street_id, " + + "sm.status_master AS status, u.is_app, DATE_FORMAT(u.close_date, '%d-%m-%Y') AS close_date, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', u.officer_upload_url) AS officer_upload_url, " + + "itm.quantity, im.item_name " + + "FROM user_request_table u " + + "LEFT JOIN items itm ON u.id = itm.req_table_id " + + "LEFT JOIN item_master im ON itm.iteam_id = im.id AND im.is_active = 1 " + + "LEFT JOIN status_master sm ON sm.id = u.status AND sm.is_active = 1 AND sm.is_delete = 0 " + + "WHERE u.zone = ? AND u.division = ? AND u.street_id = ? AND u.id = ? AND u.is_active = 1"; + } else { + params.add(id); + finalSql = "SELECT u.id, u.request_id, u.user_name, u.mobile, u.address, u.latitude, u.longitude, " + + "u.zone, u.division, u.street_name, u.remarks, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', u.image_url) AS image_url, " + + "DATE_FORMAT(u.cdate, '%d-%m-%Y') AS cdate, u.is_active, u.is_delete, u.street_id, " + + "sm.status_master AS status, u.is_app, DATE_FORMAT(u.close_date, '%d-%m-%Y') AS close_date, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', u.officer_upload_url) AS officer_upload_url, " + + "itm.quantity, im.item_name " + + "FROM user_request_table u " + + "LEFT JOIN items itm ON u.id = itm.req_table_id " + + "LEFT JOIN item_master im ON itm.iteam_id = im.id AND im.is_active = 1 " + + "LEFT JOIN status_master sm ON sm.id = u.status AND sm.is_active = 1 AND sm.is_delete = 0 " + + "WHERE u.zone = ? AND u.division = ? AND u.id = ? AND u.is_active = 1"; + } + + List> rawData = jdbcDomesticWasteTemplate.queryForList(finalSql, params.toArray()); + return groupRequestsWithItems(rawData); + } + + + public Map actionTaken(String requestId, MultipartFile imageFile, int createdBy,String latitude,String longitude ) { + try { + // Step 0: Fetch internal id using requestId + String fetchIdSql = "SELECT id FROM user_request_table WHERE request_id = ?"; + List idList = jdbcDomesticWasteTemplate.queryForList(fetchIdSql, new Object[]{requestId}, Integer.class); + if (idList.isEmpty()) { + return Map.of("status", false, "message", "No record found for the given requestId: " + requestId); + } + Integer id = idList.get(0); + + // Step 1: Upload image + String imagePath = fileUpload(imageFile, "officer_action_photo"); + + // Step 2: Insert into officer_data + String insertSql = "INSERT INTO officer_data (request_id, image_url, cdate, is_active, created_by,latitude,longitude) " + + "VALUES (?, ?, NOW(), ?, ?,?,?)"; + jdbcDomesticWasteTemplate.update(insertSql, requestId, imagePath, true, createdBy,latitude,longitude); + + // Step 3: Update user_request_table - status, officer_upload_url, and close_date from officer_data + String updateSql = "UPDATE user_request_table u " + + "JOIN officer_data o ON o.request_id = u.request_id " + + "SET u.status = '1', " + + " u.officer_upload_url = ?, " + + " u.close_date = DATE(o.cdate) " + + "WHERE u.id = ?"; + jdbcDomesticWasteTemplate.update(updateSql, imagePath, id); + + + + return Map.of("status", true, "message", "Action taken recorded successfully"); + + } catch (Exception e) { + e.printStackTrace(); + return Map.of("status", false, "message", "Error: " + e.getMessage()); + } + } + +//scheduler method + public Map updateOrderStatus(String status) { + try { + String sql = "UPDATE user_request_table " + + "SET status = ? " + + "WHERE status = '1' AND DATE(cdate) < CURDATE()";// + + int updated = jdbcDomesticWasteTemplate.update(sql, status); + + return Map.of("status", true, "message", "Order status updated", "rowsAffected", updated); + } catch (Exception e) { + e.printStackTrace(); + return Map.of("status", false, "message", "Error: " + e.getMessage()); + } + } + +//to group items and quantity common method + private List> groupRequestsWithItems(List> flatList) { + Map> groupedMap = new LinkedHashMap<>(); + + for (Map row : flatList) { + Integer id = (Integer) row.get("id"); + + if (!groupedMap.containsKey(id)) { + Map base = new LinkedHashMap<>(row); + base.remove("item_name"); + base.remove("quantity"); + base.remove("iteam_id"); + base.put("items", new ArrayList>()); + groupedMap.put(id, base); + } + + Map item = new LinkedHashMap<>(); + item.put("item_name", row.get("item_name")); + item.put("quantity", row.get("quantity")); + + ((List>) groupedMap.get(id).get("items")).add(item); + } + + //return new ArrayList<>(groupedMap.values()); + List result = new ArrayList<>(groupedMap.values()); + + if (result.isEmpty()) { + Map response = new HashMap<>(); + response.put("status", false); + response.put("message", "No data found"); + return Collections.singletonList(response); // or just `response` depending on your return type + } else { + Map response = new HashMap<>(); + response.put("status", true); + response.put("message", "Data retrieved successfully"); + response.put("data", result); + return Collections.singletonList(response); // or `response` directly + } + } + + public boolean verifylatlong(String requestId, String latitude, String longitude) { + int radius = 50; + + try { + String sql = "SELECT 1 FROM user_request_table u " + + "WHERE u.request_id = ? AND " + + "((6371008.8 * ACOS(" + + "COS(RADIANS(?)) * COS(RADIANS(u.latitude)) * COS(RADIANS(u.longitude) - RADIANS(?)) + " + + "SIN(RADIANS(?)) * SIN(RADIANS(u.latitude)))) < ?)"; + + List> rows = jdbcDomesticWasteTemplate.queryForList(sql, + requestId, latitude, longitude, latitude, radius); + + return !rows.isEmpty(); // true if one or more rows match the criteria + + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + + public Map rejectuserreq(String requestId) { + try { + // Step 0: Fetch internal id using requestId + String fetchIdSql = "SELECT id FROM user_request_table WHERE request_id = ?"; + Integer id = jdbcDomesticWasteTemplate.queryForObject(fetchIdSql, new Object[]{requestId}, Integer.class); + if (id == null) { + return Map.of("status", false, "message", "No record found for the given requestId"); + } + + // Step 1: Update using id + String sql = "UPDATE user_request_table SET status = '4' WHERE id = ?"; + jdbcDomesticWasteTemplate.update(sql, id); + + return Map.of("status", true, "message", "Rejected user request successfully"); + + } catch (Exception e) { + e.printStackTrace(); + return Map.of("status", false, "message", "Error: " + e.getMessage()); + } + } + + public Map rejectuserreqofficer(String requestId, String officer_remark, + String rejecttype, int cancelled_by, + String latitude, String longitude){ + try { + // Step 0: Fetch internal id using requestId + String fetchIdSql = "SELECT id FROM user_request_table WHERE request_id = ?"; + Integer id = jdbcDomesticWasteTemplate.queryForObject(fetchIdSql, new Object[]{requestId}, Integer.class); + if (id == null) { + return Map.of("status", false, "message", "No record found for the given requestId"); + } + + // Step 1: Proper SQL with commas + String sql = "UPDATE user_request_table SET `status` = '5', officer_remark = ?, " + + "cancelled_by = ?, rejecttype = ?, reject_latitude = ?, reject_longitude = ? WHERE id = ?"; + + jdbcDomesticWasteTemplate.update(sql, officer_remark, cancelled_by, rejecttype, latitude, longitude, id); + + return Map.of("status", true, "message", "Rejected user request successfully"); + + } catch (Exception e) { + e.printStackTrace(); + return Map.of("status", false, "message", "Error: " + e.getMessage()); + } + } +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccactivity/controller/APIActivityController.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccactivity/controller/APIActivityController.java index 56061df..fd7f23f 100644 --- a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccactivity/controller/APIActivityController.java +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccactivity/controller/APIActivityController.java @@ -1,5 +1,6 @@ package in.gov.chennaicorporation.mobileservice.gccactivity.controller; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -25,6 +26,19 @@ public class APIActivityController { return activity.getActivityCategory(departmentId); } + @GetMapping(value="/asset/checkAssetExistsCount") + public Map checkAssetExistsCount( + @RequestParam(value = "categoryId", required = false) String categoryId, + @RequestParam(value = "streetId", required = false) String streetId, + @RequestParam(value = "latitude", required = false) String latitude, + @RequestParam(value = "longitude", required = false) String longitude + ){ + int count = activity.checkAssetExistsCount(categoryId, streetId, latitude, longitude); + Map response = new HashMap<>(); + response.put("count", count); + return response; + } + @PostMapping(value="/asset/save") public List saveAsset(@RequestParam MultiValueMap formData, @RequestParam("assetTypeId") String assetTypeId, diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccactivity/service/Activity.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccactivity/service/Activity.java index e732126..ca904e7 100644 --- a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccactivity/service/Activity.java +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccactivity/service/Activity.java @@ -94,6 +94,28 @@ public class Activity { return result; } + @Transactional + public int checkAssetExistsCount(String categoryId, String streetId, String latitude, String longitude) { + String sqlQuery = "SELECT COUNT(*) " + + "FROM ( " + + " SELECT id, ST_Distance_Sphere( " + + " location, ST_GeomFromText(CONCAT('POINT(', ?, ' ', ?, ')'), 4326) " + + " ) AS distance_meters " + + " FROM asset_list " + + " WHERE streetid = ? " + + " AND category_id = ? " + + " AND isactive = 1 " + + " AND cby <> 0 " + + " HAVING distance_meters <= 3 " + + ") AS nearby_assets"; + + return jdbcActivityTemplate.queryForObject( + sqlQuery, Integer.class, + longitude, latitude, + streetId, categoryId + ); + } + @Transactional public List> saveAsset( MultiValueMap formData, @@ -113,8 +135,8 @@ public class Activity { String image = assetFileUpload(assetType,file); - String sqlQuery = "INSERT INTO `asset_list`(`category_id`, `image`, `latitude`, `longitude`, `zone`, `ward`, `streetid`, `streetname`, `cby`, `name`) " - + "VALUES (?,?,?,?,?,?,?,?,?,?)"; + String sqlQuery = "INSERT INTO `asset_list`(`category_id`, `image`, `latitude`, `longitude`, `zone`, `ward`, `streetid`, `streetname`, `cby`, `name`,`location`) " + + "VALUES (?,?,?,?,?,?,?,?,?,?, ST_GeomFromText(CONCAT('POINT(', ?, ' ', ?, ')'), 4326))"; KeyHolder keyHolder = new GeneratedKeyHolder(); @@ -133,6 +155,8 @@ public class Activity { ps.setString(8, streetName); ps.setString(9, loginId); ps.setString(10, name); + ps.setString(11, longitude); + ps.setString(12, latitude); return ps; } }, keyHolder); @@ -170,7 +194,7 @@ public class Activity { return Collections.singletonList(response); } -public String assetFileUpload(String catId, MultipartFile file) { + public String assetFileUpload(String catId, MultipartFile file) { int lastInsertId = 0; // Set the file path where you want to save it @@ -223,15 +247,137 @@ public String assetFileUpload(String catId, MultipartFile file) { //String sqlQuery = "SELECT *,CONCAT('https://gccservices.chennaicorporation.gov.in/gccofficialapp/files/"+filePath+"', image) AS imageUrl FROM `asset_list` WHERE `category_id`=? AND `streetid`=?"; /* - String sqlQuery="SELECT al.*, CONCAT('"+fileBaseUrl+"/gccofficialapp/files/', al.image) AS imageUrl, " + String sqlQuery="SELECT al.*, CONCAT('"+fileBaseUrl+"/gccofficialapp/files/asset_images/2', al.image) AS imageUrl, " + "af.feedback_date AS lastfeedbackdate FROM asset_list al " + "LEFT JOIN ( SELECT af1.*, af2.latest_feedback_date FROM activity_feedback af1 " + "INNER JOIN ( SELECT asset_id, MAX(feedback_date) AS latest_feedback_date FROM activity_feedback GROUP BY asset_id ) af2 " + "ON af1.asset_id = af2.asset_id AND af1.feedback_date = af2.latest_feedback_date ) af " + "ON al.id = af.asset_id WHERE al.category_id = ? AND al.streetid = ?"; */ + List> result; + + if ("2".equals(assetTypeId)) { + String startdate = "2025-05-18"; String sqlQuery ="SELECT " + + " al.*, " + + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files/', al.image) AS imageUrl, " + + " DATE_FORMAT(af.latest_feedback_date, '%d-%m-%Y') AS lastfeedbackdate, " + + " EXISTS (" + + " SELECT 1 FROM activity_feedback ab " + + " WHERE ab.asset_id = al.id " + + " AND ab.feedback_id = 0 " + + " AND ab.feedback_date BETWEEN ? AND NOW() " + + " ) AS is_before, " + + " EXISTS (" + + " SELECT 1 FROM activity_feedback aa " + + " WHERE aa.asset_id = al.id " + + " AND aa.feedback_id > 0 " + + " AND aa.feedback_date BETWEEN ? AND NOW() " + + " ) AS is_after " + + "FROM asset_list al " + + "LEFT JOIN (" + + " SELECT asset_id, MAX(feedback_date) AS latest_feedback_date " + + " FROM activity_feedback " + + " GROUP BY asset_id " + + ") af ON al.id = af.asset_id " + + "WHERE al.category_id = ? AND al.streetid = ? AND al.isactive=1 AND isdelete=0 "; + + result = jdbcActivityTemplate.queryForList(sqlQuery, startdate, startdate, assetTypeId, streetId); + + } else { + + /* + String sqlQuery = + "SELECT " + + " al.*, " + + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files/', al.image) AS imageUrl, " + + + " DATE_FORMAT(bf.latest_before_date, '%d-%m-%Y') AS lastfeedbackdate, " + + + " DATE_FORMAT(bf.latest_before_date, '%d-%m-%Y') AS last_before_date, " + + " CASE WHEN bf.asset_id IS NOT NULL THEN TRUE ELSE FALSE END AS has_before, " + + + " DATE_FORMAT(af.latest_after_date, '%d-%m-%Y') AS last_after_date, " + + " CASE WHEN af.asset_id IS NOT NULL THEN TRUE ELSE FALSE END AS has_after " + + + "FROM asset_list al " + + + "LEFT JOIN ( " + + " SELECT asset_id, MAX(feedback_date) AS latest_before_date " + + " FROM activity_feedback " + + " WHERE feedback_id = 0 " + + " GROUP BY asset_id " + + ") bf ON al.id = bf.asset_id " + + + "LEFT JOIN ( " + + " SELECT af.asset_id, MAX(af.feedback_date) AS latest_after_date " + + " FROM activity_feedback af " + + " INNER JOIN ( " + + " SELECT asset_id, MAX(feedback_date) AS latest_before_date " + + " FROM activity_feedback " + + " WHERE feedback_id = 0 " + + " GROUP BY asset_id " + + " ) bf_sub ON af.asset_id = bf_sub.asset_id " + + " WHERE af.feedback_id > 0 AND af.feedback_date > bf_sub.latest_before_date " + + " GROUP BY af.asset_id " + + ") af ON al.id = af.asset_id " + + + "WHERE al.category_id = ? AND al.streetid = ?"; + */ + + String sqlQuery = + "SELECT " + + " al.*, " + + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files/', al.image) AS imageUrl, " + + + // Unified last feedback date (same as old query) + " DATE_FORMAT(allf.latest_feedback_date, '%d-%m-%Y') AS lastfeedbackdate, " + + + // Latest before feedback date + " DATE_FORMAT(bf.latest_before_date, '%d-%m-%Y') AS last_before_date, " + + " CASE WHEN bf.asset_id IS NOT NULL THEN TRUE ELSE FALSE END AS is_before, " + + + // Latest after feedback date + " DATE_FORMAT(af.latest_after_date, '%d-%m-%Y') AS last_after_date, " + + " CASE WHEN af.asset_id IS NOT NULL THEN TRUE ELSE FALSE END AS is_after " + + + "FROM asset_list al " + + + // All feedback: for lastfeedbackdate + "LEFT JOIN ( " + + " SELECT asset_id, MAX(feedback_date) AS latest_feedback_date " + + " FROM activity_feedback " + + " GROUP BY asset_id " + + ") allf ON al.id = allf.asset_id " + + + // Latest before feedback (feedback_id = 0) + "LEFT JOIN ( " + + " SELECT asset_id, MAX(feedback_date) AS latest_before_date " + + " FROM activity_feedback " + + " WHERE feedback_id = 0 " + + " GROUP BY asset_id " + + ") bf ON al.id = bf.asset_id " + + + // Latest after feedback (feedback_id > 0) after the before feedback + "LEFT JOIN ( " + + " SELECT af.asset_id, MAX(af.feedback_date) AS latest_after_date " + + " FROM activity_feedback af " + + " INNER JOIN ( " + + " SELECT asset_id, MAX(feedback_date) AS latest_before_date " + + " FROM activity_feedback " + + " WHERE feedback_id = 0 " + + " GROUP BY asset_id " + + " ) bf_sub ON af.asset_id = bf_sub.asset_id " + + " WHERE af.feedback_id > 0 AND af.feedback_date > bf_sub.latest_before_date " + + " GROUP BY af.asset_id " + + ") af ON al.id = af.asset_id " + + + "WHERE al.category_id = ? AND al.streetid = ? AND al.isactive=1 AND isdelete=0 "; + + result = jdbcActivityTemplate.queryForList(sqlQuery, assetTypeId, streetId); + /* + String sqlQuery ="SELECT " + " al.*, " + " CONCAT('"+fileBaseUrl+"/gccofficialapp/files/', al.image) AS imageUrl, " + " DATE_FORMAT(af.latest_feedback_date, '%d-%m-%Y') AS lastfeedbackdate, " @@ -254,7 +400,7 @@ public String assetFileUpload(String catId, MultipartFile file) { + ") af ON al.id = af.asset_id " + "LEFT JOIN ( " + " SELECT " - + " asset_id, " + + " id, asset_id, " + " 1 AS has_before " + " FROM activity_feedback " + " WHERE feedback_id = 0 " @@ -263,13 +409,17 @@ public String assetFileUpload(String catId, MultipartFile file) { + "LEFT JOIN ( " + " SELECT " + " asset_id, " - + " 1 AS has_after " + + " 1 AS has_after," + + " feedback_id " + " FROM activity_feedback " + " WHERE feedback_id > 0 " + " GROUP BY asset_id " - + ") aa ON al.id = aa.asset_id " + + ") aa ON ab.id = aa.feedback_id " + " WHERE al.category_id = ? AND al.streetid = ?"; - List> result = jdbcActivityTemplate.queryForList(sqlQuery,assetTypeId,streetId); + */ + //result = jdbcActivityTemplate.queryForList(sqlQuery, assetTypeId,streetId); + } + return result; } @@ -539,11 +689,24 @@ public String assetFileUpload(String catId, MultipartFile file) { @Transactional public List> loadAssetLastFeedbackHistoryByUser(String catId, String assetId, String loginId) { // Query to get the last feedback by user for the given asset - String sqlQuery = "SELECT * FROM `activity_feedback` WHERE (`isactive`=1 AND `isdelete`=0) " - + "AND (`asset_id`=? AND `feedback_by`=?) ORDER BY `feedback_date` DESC LIMIT 1"; - - // Execute the query and get the result - List> result = jdbcActivityTemplate.queryForList(sqlQuery, assetId, loginId); + List> result; + if ("2".equals(catId)) { + String sqlQuery = "SELECT * FROM `activity_feedback` WHERE (`isactive`=1 AND `isdelete`=0) " + + "AND (`asset_id`=? " + // + "AND `feedback_by`=?" + + ") " + + "ORDER BY `id` DESC LIMIT 1"; + + // Execute the query and get the result + result = jdbcActivityTemplate.queryForList(sqlQuery, assetId); + } + else { + String sqlQuery = "SELECT * FROM `activity_feedback` WHERE (`isactive`=1 AND `isdelete`=0) " + + "AND (`asset_id`=? AND `feedback_by`=?) ORDER BY `feedback_date` DESC LIMIT 1"; + + // Execute the query and get the result + result = jdbcActivityTemplate.queryForList(sqlQuery, assetId, loginId); + } String feedback_id = "0"; if (result.isEmpty()) { @@ -579,11 +742,27 @@ public String assetFileUpload(String catId, MultipartFile file) { @Transactional public List> loadAssetLastFeedbackByUser(String catId, String assetId, String loginId) { // Query to get the last feedback by user for the given asset + List> result; + if ("2".equals(catId)) { String sqlQuery = "SELECT * FROM `activity_feedback` WHERE (`isactive`=1 AND `isdelete`=0) " - + "AND (`asset_id`=? AND `feedback_by`=?) ORDER BY `feedback_date` DESC LIMIT 1"; + + "AND (`asset_id`=? " + // + "AND `feedback_by`=?" + + ") " + + "ORDER BY `id` DESC LIMIT 1"; // Execute the query and get the result - List> result = jdbcActivityTemplate.queryForList(sqlQuery, assetId, loginId); + result = jdbcActivityTemplate.queryForList(sqlQuery, assetId); + } + else { + String sqlQuery = "SELECT * FROM `activity_feedback` WHERE (`isactive`=1 AND `isdelete`=0) " + + "AND (`asset_id`=? " + + "AND `feedback_by`=?" + + ") " + + "ORDER BY `id` DESC LIMIT 1"; + + // Execute the query and get the result + result = jdbcActivityTemplate.queryForList(sqlQuery, assetId, loginId); + } String feedback_id = "0"; if (result.isEmpty()) { @@ -643,11 +822,39 @@ public String assetFileUpload(String catId, MultipartFile file) { return result; } - - + /* + public int getZoneAssetCount(int catid, String zone) { + String sqlQuery = "SELECT SUM(`totalcount`) as Total FROM `asset_count_master` WHERE catid=? and zone=?"; + + List> taskResult = jdbcActivityTemplate.queryForList(sqlQuery, catid, zone); + + if (!taskResult.isEmpty() && taskResult.get(0).get("Total") != null) { + return ((Number) taskResult.get(0).get("Total")).intValue(); + } else { + return 0; + } + } + + public int getZoneAssetCount(int catid, String zone, String ward) { + String sqlQuery = "SELECT SUM(`totalcount`) as Total FROM `asset_count_master` WHERE catid=? AND zone=? AND ward=?"; + + List> taskResult = jdbcActivityTemplate.queryForList(sqlQuery, catid, zone, ward); + + if (!taskResult.isEmpty() && taskResult.get(0).get("Total") != null) { + return ((Number) taskResult.get(0).get("Total")).intValue(); + } else { + return 0; + } + } + */ + private int getInt(Object val) { + return val instanceof Number ? ((Number) val).intValue() : 0; + } + // For report and Dashboard + + - @Transactional public Map filterReports( String assetType, @@ -670,13 +877,23 @@ public String assetFileUpload(String catId, MultipartFile file) { //sqlQuery.append(" AND al.streetid = ?"); } - + String ExtraSQL=" COALESCE(SUM(CASE WHEN aff.fileaction = 'before' THEN 1 ELSE 0 END), 0) AS total_started, " + + " COALESCE(SUM(CASE WHEN aff.fileaction = 'after' THEN 1 ELSE 0 END), 0) AS total_completed, "; + // if(assetType.equalsIgnoreCase("2")) { + if ("2".equals(assetType)) { + ExtraSQL=" 0 AS total_started, " + + " COALESCE(SUM(CASE WHEN aff.fileaction IN ('after', 'before') THEN 1 ELSE 0 END), 0) AS total_completed, "; + } + // Start constructing the SQL query StringBuilder sqlQuery = new StringBuilder("SELECT " + + groupQuery - + " ,COUNT(DISTINCT al.id) AS total_assets, " - + " COALESCE(SUM(CASE WHEN aff.fileaction = 'before' THEN 1 ELSE 0 END), 0) AS total_started, " - + " COALESCE(SUM(CASE WHEN aff.fileaction = 'after' THEN 1 ELSE 0 END), 0) AS total_completed, " + + " ,COUNT( CONCAT(al.latitude, ',', al.longitude)) AS total_assets, " + //+ " ,COUNT(DISTINCT CONCAT(al.latitude, ',', al.longitude)) AS total_assets, " + //+ " COALESCE(SUM(CASE WHEN aff.fileaction = 'before' THEN 1 ELSE 0 END), 0) AS total_started, " + //+ " COALESCE(SUM(CASE WHEN aff.fileaction = 'after' THEN 1 ELSE 0 END), 0) AS total_completed, " + + ExtraSQL + " COALESCE(COUNT(DISTINCT al.id) - " + " SUM(CASE WHEN aff.fileaction = 'before' THEN 1 ELSE 0 END) - " + " SUM(CASE WHEN aff.fileaction = 'after' THEN 1 ELSE 0 END), 0) AS total_pending " @@ -691,11 +908,13 @@ public String assetFileUpload(String catId, MultipartFile file) { + " INNER JOIN " + " (SELECT asset_id, MAX(feedback_date) AS latest_feedback_date " + " FROM activity_feedback " - + " WHERE 1=1 "); + + " WHERE isactive=1 "); + // Add date range filter if both fromDate and toDate are provided - if (fromDate != null && toDate != null) { - sqlQuery.append(" AND feedback_date BETWEEN ? AND ?"); + if (fromDate != null && !fromDate.trim().isEmpty() && + toDate != null && !toDate.trim().isEmpty()) { + sqlQuery.append(" AND DATE(feedback_date) BETWEEN ? AND ?"); } sqlQuery.append(" GROUP BY asset_id) latest_feedback_dates " @@ -709,18 +928,33 @@ public String assetFileUpload(String catId, MultipartFile file) { // Add additional filters if provided if (zone != null && !zone.isEmpty() && !zone.isBlank()) { - sqlQuery.append(" AND al.zone = ?"); + sqlQuery.append(" AND al.zone = ? "); } if (ward != null && !ward.isEmpty() && !ward.isBlank()) { - sqlQuery.append(" AND al.ward = ?"); + sqlQuery.append(" AND al.ward = ? "); } if (streetid != null && !streetid.isEmpty() && !streetid.isBlank()) { - sqlQuery.append(" AND al.streetid = ?"); + sqlQuery.append(" AND al.streetid = ? "); } if (assetType != null && !assetType.isEmpty() && !assetType.isBlank()) { - sqlQuery.append(" AND al.category_id = ?"); + sqlQuery.append(" AND al.category_id = ? "); } + sqlQuery.append(" AND al.isactive = 1 AND al.isdelete = 0 "); + + /* + if(assetType != null && !assetType.isEmpty() && !assetType.isBlank() && "2".equals(assetType)) + { + sqlQuery.append(" AND ((DATE(al.cdate) > '2024-08-01' AND DATE(al.cdate) <= '2025-06-12' AND al.zone IN (1,2,3,4,5,6,7)) OR\n" + + " (DATE(al.cdate) > '2025-05-01' AND DATE(al.cdate) <= '2025-06-12' AND al.zone = 8) OR\n" + + " (DATE(al.cdate) > '2025-05-20' AND DATE(al.cdate) <= '2025-06-12' AND al.zone = 9) OR\n" + + " (DATE(al.cdate) > '2024-09-06' AND DATE(al.cdate) <= '2025-06-12' AND al.zone IN (10)) OR\n" + + " (DATE(al.cdate) > '2024-10-01' AND DATE(al.cdate) <= '2025-06-12' AND al.zone IN (11)) OR\n" + + " (DATE(al.cdate) > '2024-09-01' AND DATE(al.cdate) <= '2025-06-12' AND al.zone IN (12)) OR\n" + + " (DATE(al.cdate) > '2024-05-03' AND DATE(al.cdate) <= '2025-06-12' AND al.zone IN (13,14,15))\n" + + " )"); + } + */ // Group by zone sqlQuery.append(" GROUP BY "+groupQuery); @@ -730,7 +964,8 @@ public String assetFileUpload(String catId, MultipartFile file) { // Prepare parameters List params = new ArrayList<>(); - if (fromDate != null && toDate != null) { + if (fromDate != null && !fromDate.trim().isEmpty() && + toDate != null && !toDate.trim().isEmpty()) { System.out.println("filterReports:"); System.out.println("From Date:" + fromDate); System.out.println("To Date:" + toDate); @@ -738,11 +973,14 @@ public String assetFileUpload(String catId, MultipartFile file) { fromDate = convertDateFormat(fromDate,0); toDate = convertDateFormat(toDate,0); - fromDate = fromDate + " 00:00:00"; - toDate = toDate + " 23:59:59"; + //fromDate = fromDate + " 00:00:00"; + //toDate = toDate + " 23:59:59"; params.add(fromDate); params.add(toDate); + System.out.println("After - filterReports:"); + System.out.println("After From Date:" + fromDate); + System.out.println("After To Date:" + toDate); } if (zone != null && !zone.isEmpty() && !zone.isBlank()) { params.add(zone); @@ -759,75 +997,137 @@ public String assetFileUpload(String catId, MultipartFile file) { // Execute query System.out.println(sqlQuery.toString()); // For debugging - List> result = jdbcActivityTemplate.queryForList(sqlQuery.toString(), params.toArray()); + List> result = jdbcActivityTemplate.queryForList(sqlQuery.toString(), params.toArray()); - // Overall totals query - StringBuilder sqlQueryOverall = new StringBuilder("SELECT " - + " COUNT(DISTINCT al.id) AS total_assets, " - + " COALESCE(SUM(CASE WHEN aff.fileaction = 'before' THEN 1 ELSE 0 END), 0) AS total_started, " - + " COALESCE(SUM(CASE WHEN aff.fileaction = 'after' THEN 1 ELSE 0 END), 0) AS total_completed, " - + " COALESCE(COUNT(DISTINCT al.id) - " - + " SUM(CASE WHEN aff.fileaction = 'before' THEN 1 ELSE 0 END) - " - + " SUM(CASE WHEN aff.fileaction = 'after' THEN 1 ELSE 0 END), 0) AS total_pending " - + "FROM " - + " asset_list al " - + "LEFT JOIN " - + " (SELECT " - + " af.id, " - + " af.asset_id " - + " FROM " - + " activity_feedback af " - + " INNER JOIN " - + " (SELECT asset_id, MAX(feedback_date) AS latest_feedback_date " - + " FROM activity_feedback " - + " WHERE 1=1 "); - - // Add date range filter if both fromDate and toDate are provided - if (fromDate != null && toDate != null) { - sqlQueryOverall.append(" AND feedback_date BETWEEN ? AND ?"); + if ("2".equals(assetType)) { + if ((zone == null || zone.isBlank()) && (ward == null || ward.isBlank())) { + + String sqlMaster = "SELECT zone, SUM(totalcount) as master_total FROM asset_count_master WHERE catid = 2 GROUP BY zone"; + List> masterTotals = jdbcActivityTemplate.queryForList(sqlMaster); + + // Convert to Map for fast lookup by zone + Map masterMap = new HashMap<>(); + for (Map row : masterTotals) { + String zoneName = (String) row.get("zone"); + Number count = (Number) row.get("master_total"); + masterMap.put(zoneName, count != null ? count.intValue() : 0); + } + + // Merge into zoneWise result + for (Map zoneEntry : result) { + String zoneName = (String) zoneEntry.get("zone"); + Integer masterTotal = masterMap.getOrDefault(zoneName, 0); + zoneEntry.put("master_total", masterTotal); + } + + } + + if (zone != null && !zone.isEmpty() && !zone.isBlank()) { + + String sqlMaster2 = "SELECT division as ward, SUM(totalcount) as master_total FROM asset_count_master WHERE catid = 2 AND zone = ? GROUP BY division;"; + List> wardmasterTotals = jdbcActivityTemplate.queryForList(sqlMaster2,zone); + + // Convert to Map for fast lookup by ward + Map masterMapWard = new HashMap<>(); + for (Map row : wardmasterTotals) { + String wardName = (String) row.get("ward"); + Number count = (Number) row.get("master_total"); + masterMapWard.put(wardName, count != null ? count.intValue() : 0); + } + + // Merge into zoneWise result + for (Map zoneEntry : result) { + String wardName = (String) zoneEntry.get("ward"); + Integer masterTotal = masterMapWard.getOrDefault(wardName, 0); + zoneEntry.put("master_total", masterTotal); + } + } } - sqlQueryOverall.append(" GROUP BY asset_id) latest_feedback_dates " - + " ON " - + " af.asset_id = latest_feedback_dates.asset_id " - + " AND af.feedback_date = latest_feedback_dates.latest_feedback_date " - + " ) latest_feedback ON al.id = latest_feedback.asset_id AND (al.isactive=1 AND al.isdelete=0) " - + "LEFT JOIN " - + " activity_feedback_file aff ON latest_feedback.id = aff.feedback_id " - + "WHERE 1=1 "); - - // Add additional filters if provided - if (zone != null && !zone.isEmpty() && !zone.isBlank()) { - sqlQueryOverall.append(" AND al.zone = ?"); - } - if (ward != null && !ward.isEmpty() && !ward.isBlank()) { - sqlQueryOverall.append(" AND al.ward = ?"); - } - if (streetid != null && !streetid.isEmpty() && !streetid.isBlank()) { - sqlQueryOverall.append(" AND al.streetid = ?"); + for (Map masterEntry : result) { + Number totalAssets = (Number) masterEntry.get("total_assets"); + Number masterTotal = (Number) masterEntry.get("master_total"); + + int total = totalAssets != null ? totalAssets.intValue() : 0; + int master = masterTotal != null ? masterTotal.intValue() : 0; + + int remainingAssets = master - total; + masterEntry.put("remaining_assets", remainingAssets); } - if (assetType != null && !assetType.isEmpty() && !assetType.isBlank()) { - sqlQueryOverall.append(" AND al.category_id = ?"); + if ((streetid == null || streetid.isBlank()) && (ward == null || ward.isBlank())) { + Map footerTotal = new HashMap<>(); + footerTotal.put("zone", "Total"); + footerTotal.put("ward", "Total"); + + int totalAssetsSum = 0; + int totalStartedSum = 0; + int totalCompletedSum = 0; + int totalPendingSum = 0; + int masterTotalSum = 0; + int remainingAssetsSum = 0; + + for (Map entry : result) { + totalAssetsSum += getInt(entry.get("total_assets")); + totalStartedSum += getInt(entry.get("total_started")); + totalCompletedSum += getInt(entry.get("total_completed")); + totalPendingSum += getInt(entry.get("total_pending")); + masterTotalSum += getInt(entry.get("master_total")); + remainingAssetsSum += getInt(entry.get("remaining_assets")); + } + + footerTotal.put("total_assets", totalAssetsSum); + footerTotal.put("total_started", totalStartedSum); + footerTotal.put("total_completed", totalCompletedSum); + footerTotal.put("total_pending", totalPendingSum); + footerTotal.put("master_total", masterTotalSum); + footerTotal.put("remaining_assets", remainingAssetsSum); + + // Append to result + result.add(footerTotal); + } + // --- Overall totals from zoneWise --- + int totalAssetsSum = 0; + int totalStartedSum = 0; + int totalCompletedSum = 0; + int totalPendingSum = 0; + int masterTotalSum = 0; + int remainingAssetsSum = 0; + + for (Map entry : result) { + totalAssetsSum += getInt(entry.get("total_assets")); + totalStartedSum += getInt(entry.get("total_started")); + totalCompletedSum += getInt(entry.get("total_completed")); + totalPendingSum += getInt(entry.get("total_pending")); + masterTotalSum += getInt(entry.get("master_total")); + remainingAssetsSum+= getInt(entry.get("remaining_assets")); } - - // Add HAVING clause to filter out rows where total_started and total_completed are both zero - sqlQueryOverall.append(" HAVING (COALESCE(SUM(CASE WHEN aff.fileaction = 'before' THEN 1 ELSE 0 END), 0) > 0 OR " - + "COALESCE(SUM(CASE WHEN aff.fileaction = 'after' THEN 1 ELSE 0 END), 0) > 0)"); - - // Execute overall query - List> overallResult = jdbcActivityTemplate.queryForList(sqlQueryOverall.toString(), params.toArray()); - - + + Map overallTotals = new HashMap<>(); + overallTotals.put("total_assets", totalAssetsSum); + overallTotals.put("total_started", totalStartedSum); + overallTotals.put("total_completed", totalCompletedSum); + overallTotals.put("total_pending", totalPendingSum); + overallTotals.put("master_total", masterTotalSum); + overallTotals.put("remaining_assets", remainingAssetsSum); + + // --- Final result --- + Map result2 = new HashMap<>(); + result2.put("zoneWise", result); + result2.put("overallTotals", overallTotals); + + return result2; + /* // Combine results Map result2 = new HashMap<>(); result2.put("zoneWise", result); result2.put("overallTotals", overallResult.isEmpty() ? Collections.singletonMap("total_started", 0) : overallResult.get(0)); - return result2; + return result2;*/ } + @Transactional public List> filterReportsByDate( @@ -867,6 +1167,7 @@ public String assetFileUpload(String catId, MultipartFile file) { + " AND `asset_list`.`streetid` = ? " + " AND `asset_list`.`isactive` = 1 " + " AND `asset_list`.`isdelete` = 0 " + + " AND `activity_feedback`.`isactive` = 1 " + "GROUP BY " + " `asset_list`.`id`"; @@ -944,7 +1245,7 @@ public String assetFileUpload(String catId, MultipartFile file) { + " `activity_feedback` " + "JOIN " + " `asset_list` ON `asset_list`.`id` = `activity_feedback`.`asset_id` " - + "WHERE 1=1 "); + + "WHERE activity_feedback.isactive=1 "); @@ -1129,4 +1430,6 @@ public String assetFileUpload(String catId, MultipartFile file) { return ""; } + + } diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gcceducation/service/EducationActivity.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gcceducation/service/EducationActivity.java index cb7b50a..5a6d20f 100644 --- a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gcceducation/service/EducationActivity.java +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gcceducation/service/EducationActivity.java @@ -18,6 +18,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Random; @@ -202,13 +203,14 @@ public class EducationActivity { return Collections.singletonList(response); } + public List> getSchoolList( MultiValueMap formData, String latitude, String longitude, String loginid ) { - + String sqlWhere = ""; String radius = getConfigValue(); @@ -435,6 +437,8 @@ public class EducationActivity { + " ql.floors_id, " + " ql.room_id, " + " ql.othercond, " + + " ql.is_value_boolen, " + + " ql.parent_condition, " + " ql.feedback_column as return_name, " + " CASE " @@ -444,7 +448,7 @@ public class EducationActivity { + " 'english_name', qov.english_name, " + " 'tamil_name', qov.tamil_name, " + " 'value', qov.value, " - //+ " 'isactive', qov.isactive, " + + " 'ex_function', qov.ex_function, " //+ " 'isdelete', qov.isdelete " + " 'orderby', qov.orderby " + " ) " @@ -470,7 +474,11 @@ public class EducationActivity { List> result = jdbcEducationTemplate.queryForList(sql,menu_id, "%" + qtype + "%"); ObjectMapper mapper = new ObjectMapper(); - for (Map row : result) { + //for (Map row : result) { + Iterator> iterator = result.iterator(); + + while (iterator.hasNext()) { + Map row = iterator.next(); Object optionsRaw = row.get("options"); if (optionsRaw != null && optionsRaw instanceof String) { try { @@ -492,7 +500,31 @@ public class EducationActivity { String tableName = (String) row.get("view_table_name"); String fieldName = (String) row.get("view_field_name"); String whereCond = (String) row.get("othercond"); + + String excludeQuestionQuery = (String) row.get("parent_condition"); + System.out.println("parent_condition : "+excludeQuestionQuery); + if (excludeQuestionQuery != null && !excludeQuestionQuery.trim().isEmpty()) { + try { + if (excludeQuestionQuery != null && excludeQuestionQuery.contains("+school_details_id+")) { + excludeQuestionQuery = excludeQuestionQuery.replace("+school_details_id+", school_details_id); + } + System.out.println("Final SQL: " + excludeQuestionQuery); + + List> excluderesult = jdbcEducationTemplate.queryForList(excludeQuestionQuery); + System.out.println("excluderesult : "+excluderesult); + if (excluderesult == null || excluderesult.isEmpty()) { + iterator.remove(); // ❗️ Remove the row if no result + continue; + } + } catch (Exception e) { + // Handle or log the invalid SQL + System.out.println("Invalid SQL in excludeQuestionQuery: " + excludeQuestionQuery); + System.out.println("Error: " + e.getMessage()); + iterator.remove(); // ❗️ Optionally remove if SQL is bad + continue; + } + } if (tableName != null && fieldName != null) { StringBuilder whereClause = new StringBuilder(" WHERE 1=1 "); List params = new ArrayList<>(); @@ -502,7 +534,12 @@ public class EducationActivity { if (schoolIdFlag) { String schoolIdVal = school_details_id; if(schoolIdVal != null) { - whereClause.append(" AND school_id = ?"); + if (tableName != null && tableName.contains("_feedback")) { + whereClause.append(" AND school_details_id = ?"); + } + else { + whereClause.append(" AND school_id = ?"); + } params.add(schoolIdVal); } } @@ -535,10 +572,12 @@ public class EducationActivity { } } + //whereClause.append("ORDER BY `id` DESC limit 1"); + String whereCondQuery =""; System.out.println("whereCond: "+whereCond); if (whereCond != null && !whereCond.trim().isEmpty()) { - whereCondQuery = " AND ("+whereCond+")"; + whereCondQuery = " AND "+whereCond+""; } if (!params.isEmpty()) { @@ -555,12 +594,33 @@ public class EducationActivity { String query = String.format("SELECT %s AS val FROM %s %s %s", fieldName, tableName, whereClause.toString(), whereCondQuery); - List values = jdbcEducationTemplate.query(query, params.toArray(), (rs, rowNum) -> rs.getString("val")); + //List values = jdbcEducationTemplate.query(query, params.toArray(), (rs, rowNum) -> rs.getString("val")); + List values = jdbcEducationTemplate.query(query, params.toArray(), (rs, rowNum) -> { + String val = rs.getString("val"); + if (fieldName.contains("_file")) { + return "https://gccservices.in/gccofficialapp/files" + val; + } else { + Boolean booleanFlag = row.get("is_value_boolen") instanceof Boolean && (Boolean) row.get("is_value_boolen"); + System.out.println("is_value_boolen : "+row.get("is_value_boolen")); + System.out.println("Getting val : "+val); + if (booleanFlag) { + if ("1".equals(val) || "true".equalsIgnoreCase(val)) { + return "Yes"; + } else { + return "No"; + } + } else { + return val; + } + } + }); String joinedValues = String.join(",", values); row.put("q_display_value", joinedValues.isEmpty() ? "" : joinedValues); + + // FOR ERROR CHECK String reconstructedQuery = query; for (Object param : params) { diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccparks/service/ParksService.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccparks/service/ParksService.java index 7893aec..3ba4dee 100644 --- a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccparks/service/ParksService.java +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccparks/service/ParksService.java @@ -1643,18 +1643,32 @@ public class ParksService { public List> getWishtreeZoneCount(String fromdate, String todate, String enumeration_type) { - String sql = "SELECT tree_zone,count(tree_Id) as count FROM treeplaintandpruning " + String sql = "SELECT " + + " tree_zone," + + " COUNT(tree_id) AS count," + + " SUM(No_of_trees_required) AS assigned," + + " SUM(No_of_trees) AS completed," + + " (SUM(No_of_trees_required) - SUM(No_of_trees)) AS pending " + + "FROM " + + " treeplaintandpruning " + " where tree_enumeration_id=(?) and DATE(tree_cdate) between STR_TO_DATE('" + fromdate + "', '%d-%m-%Y') " - + "and STR_TO_DATE('" + todate + "', '%d-%m-%Y') group by tree_zone "; + + "and STR_TO_DATE('" + todate + "', '%d-%m-%Y') group by tree_zone Order By tree_zone"; return jdbcParkseTemplate.queryForList(sql, new Object[] { enumeration_type}); } public List> getTreewardCount(String zone, String fromdate, String todate, String enumeration_type) { - String sql = "SELECT tree_ward, COUNT(tree_Id) AS count " + "FROM treeplaintandpruning " + String sql = "SELECT " + + " tree_ward," + + " COUNT(tree_id) AS count," + + " SUM(No_of_trees_required) AS assigned," + + " SUM(No_of_trees) AS completed," + + " (SUM(No_of_trees_required) - SUM(No_of_trees)) AS pending " + + "FROM " + + " treeplaintandpruning " + "WHERE tree_zone = ? AND DATE(tree_cdate) BETWEEN STR_TO_DATE('" + fromdate + "', '%d-%m-%Y') AND " - + "STR_TO_DATE('" + todate + "', '%d-%m-%Y')and tree_enumeration_id=(?) GROUP BY tree_ward"; + + "STR_TO_DATE('" + todate + "', '%d-%m-%Y')and tree_enumeration_id=(?) GROUP BY tree_ward Order By tree_ward"; return jdbcParkseTemplate.queryForList(sql, new Object[] { zone, enumeration_type }); } @@ -1662,13 +1676,21 @@ public class ParksService { public List> getwardWishTreedata(String ward) { String sql = "SELECT tree.tree_Id,tree.No_of_trees_required,tree.No_of_trees,tree.tree_enumeration_id,tree.tree_zone,tree.tree_ward," + "CONCAT('" + fileBaseUrl - + "/gccofficialapp/files', image.tr_image) AS imageUrl FROM treeplaintandpruning AS tree " + + "/gccofficialapp/files', image.tr_image) AS imageUrl, " + + " SUM(tree.No_of_trees_required) AS assigned," + + " SUM(tree.No_of_trees) AS completed," + + " (SUM(tree.No_of_trees_required) - SUM(tree.No_of_trees)) AS pending " + + "FROM treeplaintandpruning AS tree " + "LEFT JOIN tree_image AS image ON image.tree_enumeration_id = tree.tree_Id WHERE tree.tree_ward =? "; return jdbcParkseTemplate.queryForList(sql, new Object[] { ward }); } public List> getTreeWardWiseCountDetails(String ward, String enumeration_type, String fromdate,String todate) { - String sql = "select tree_Id, tree_ward, coalesce(tr_parkname,tree_location) as location, count(tree_Id) as count from treeplaintandpruning " + String sql = "select tree_Id, tree_ward, coalesce(tr_parkname,tree_location) as location, count(tree_Id) as count, " + + " SUM(No_of_trees_required) AS assigned," + + " SUM(No_of_trees) AS completed," + + " (SUM(No_of_trees_required) - SUM(No_of_trees)) AS pending " + + "FROM treeplaintandpruning " + "where tree_ward=? and tree_enumeration_id = ? and date(tree_cdate) between STR_TO_DATE('" + fromdate + "', '%d-%m-%Y') and " + "STR_TO_DATE('" + todate + "', '%d-%m-%Y') group by tree_Id, tree_ward, location"; @@ -1899,8 +1921,8 @@ public class ParksService { } public List> getparkNameByRadius(String tree_latitude, String tree_longitude) { - String sql = " SELECT enumeration_Id, park_name\n" + " FROM enumeration_master WHERE\n" - + " ((6371008.8 * acos( ROUND(cos(radians(?)) * cos(radians(latitude)) * cos(radians(longitude) - radians(?)) +\n" + String sql = " SELECT `enumeration_Id`, `park_name`" + " FROM enumeration_master WHERE " + + " ((6371008.8 * acos( ROUND(cos(radians(?)) * cos(radians(latitude)) * cos(radians(longitude) - radians(?)) + " + " sin(radians(?)) * sin(radians(latitude)), 9) )) < 500) and park_name is not null"; return jdbcParkseTemplate.queryForList(sql, new Object[] { tree_latitude, tree_longitude, tree_latitude }); diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccpothole/controller/PotholeApiController.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccpothole/controller/PotholeApiController.java new file mode 100644 index 0000000..11e4c75 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccpothole/controller/PotholeApiController.java @@ -0,0 +1,531 @@ +package in.gov.chennaicorporation.mobileservice.gccpothole.controller; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import in.gov.chennaicorporation.mobileservice.gccpothole.service.PotholeService; + + +@RequestMapping("/gccofficialapp/api/pothole") +@RestController("gccofficialapppothole") + +public class PotholeApiController { + + + @Autowired + private PotholeService potholeService; + + + @PostMapping("/save-complaint") + public ResponseEntity> saveNewComplaints( + + @RequestParam("zone") String zone, + @RequestParam("ward") String ward, + @RequestParam(required = false, name = "latitude") String latitude, + @RequestParam(required = false, name = "longitude") String longitude, + @RequestParam(required = false, name = "length") String length, + @RequestParam(required = false, name = "width") String width, + @RequestParam(required = false, name = "area") String area, + @RequestParam("case_id") String caseId, + @RequestParam("street_id") String streetId, + @RequestParam("street_name") String streetName, + @RequestParam("status_id") String statusId, + @RequestParam(required = true, name = "complaint_photo") MultipartFile complaintPhoto, + @RequestParam("login_id") String loginId, + @RequestParam(required = false, name = "user_length") String userLength, + @RequestParam(required = false, name = "user_width") String userWidth, + @RequestParam(required = false, name = "user_height") String userHeight, + @RequestParam("risk_level") String riskLevel, + @RequestParam(required = false, name = "damage_type") String damage_type) { + + // File upload paths + String complaintPhotoPath = (complaintPhoto != null) ? + potholeService.fileUpload(complaintPhoto, "complaint_photo") : ""; + + // Save to DB + String saveStatus = potholeService.saveComplaintDetails( + zone, ward, latitude, longitude, length, width, area, streetId, + streetName, statusId, complaintPhotoPath, loginId, caseId, userLength, userWidth, userHeight, riskLevel, damage_type); + + Map response = new HashMap<>(); + if (saveStatus == null || saveStatus.isEmpty() || saveStatus.equals("error")) { + response.put("status", false); + response.put("message", "failed"); + response.put("description", "Failed to save the details"); + return ResponseEntity.ok(response); + } else if (saveStatus.equals("duplicate")) { + response.put("status", false); + response.put("message", "failed"); + response.put("description", "Complaints already exist"); + return ResponseEntity.ok(response); + } + + response.put("status", true); + response.put("message", "success"); + response.put("description", "Details were saved successfully"); + return ResponseEntity.ok(response); + } + + // Status Master + @GetMapping("/status") + public List> getAllStatus() { + return potholeService.getAllStatus(); + } + + // AE Complaint List against ward + @GetMapping("/aecomplaintlist") + public ResponseEntity> getComplaintsByWard(@RequestParam("aeUserId") String aeUserId) { + List> result = potholeService.getComplaintsByWard(aeUserId); + + + Map response = new HashMap<>(); + if (result.isEmpty()) { + response.put("status", false); + response.put("message", "No data found"); + response.put("data", Collections.emptyList()); + } else { + response.put("status", true); + response.put("message", "Data found"); + response.put("data", result); + } + + //System.out.println("result: " + result); + return ResponseEntity.ok(response); + } + + // Vendor Complaint List against ward + @GetMapping("/vendor") + public ResponseEntity> getComplaintsByVendor(@RequestParam("vendorUserId") String vendorUserId) { + List> result = potholeService.getComplaintsByVendorId(vendorUserId); + + Map response = new HashMap<>(); + if (result.isEmpty()) { + response.put("status", false); + response.put("message", "No data found"); + response.put("data", Collections.emptyList()); + } else { + response.put("status", true); + response.put("message", "Data found"); + response.put("data", result); + } + + return ResponseEntity.ok(response); + } + + // My Complaint List + @GetMapping("/viewRequestList") + public ResponseEntity> viewRequestList(@RequestParam("loginId") String loginId) { + + List> result = potholeService.getRequestList(loginId); + + Map response = new HashMap<>(); + if (result.isEmpty()) { + response.put("status", false); + response.put("message", "No data found"); + response.put("data", Collections.emptyList()); + } else { + response.put("status", true); + response.put("message", "Data found"); + response.put("data", result); + } + + return ResponseEntity.ok(response); + + } + + // Vendor Update + + @PostMapping("/updateComplaint") + public ResponseEntity> updateComplaint(@RequestParam("zone") String zone, + @RequestParam("ward") String ward, @RequestParam(name = "latitude") String latitude, + @RequestParam(name = "longitude") String longitude, + @RequestParam(required = false, name = "length") String length, + @RequestParam(required = false, name = "width") String width, + @RequestParam(required = false, name = "area") String area, + @RequestParam("street_id") String streetId, + @RequestParam("street_name") String streetName, + @RequestParam("status_id") String statusId, + @RequestParam("complaint_photo") MultipartFile vendorPhoto, + @RequestParam("login_id") String loginId, + @RequestParam("complaint_no") String complaint_no, + @RequestParam(required = false, name = "vendor_length") String vendorLength, + @RequestParam(required = false, name = "vendor_width") String vendorWidth, + @RequestParam(required = false, name = "vendor_height") String vendorHeight, + @RequestParam(required = false, name = "ae_length") String aeLength, + @RequestParam(required = false, name = "ae_width") String aeWidth, + @RequestParam(required = false, name = "ae_height") String aeHeight) { + + Map response = new HashMap<>(); + + String vendorPhotoPath = null; + //LocalDate updatedDate = LocalDate.now(); + LocalDateTime updatedDate = LocalDateTime.now(); + + if (statusId.equals("2")) { + vendorPhotoPath = (vendorPhoto != null) ? potholeService.fileUpload(vendorPhoto, "vendor_photo") : ""; + + } else if (statusId.equals("4")) { + vendorPhotoPath = (vendorPhoto != null) ? potholeService.fileUpload(vendorPhoto, "rectified_photo") : ""; + + } else if (statusId.equals("3")) { + vendorPhotoPath = (vendorPhoto != null) ? potholeService.fileUpload(vendorPhoto, "reopen_photo") : ""; + + } else if (statusId.equals("5")) { + vendorPhotoPath = (vendorPhoto != null) ? potholeService.fileUpload(vendorPhoto, "completed_photo") : ""; + + } else { + vendorPhotoPath = null; + + } + + String updationStatus = potholeService.updateComplaintbyVendor(statusId, loginId, updatedDate, vendorLength, vendorWidth, vendorHeight, + vendorPhotoPath, aeLength, aeWidth, aeHeight, complaint_no); + + if (updationStatus.equals("Success")) { + response.put("status", true); + response.put("message", "success"); + response.put("description", "Details were saved successfully"); + System.out.println(response); + return ResponseEntity.ok(response); + } + + response.put("status", false); + response.put("message", "Failed to update complaint Details"); + //System.err.println("Pot Hole : "+ updationStatus); + return ResponseEntity + .status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(response); + + } + + @GetMapping("/validateLocation") + public ResponseEntity> validateLocation(@RequestParam(name = "latitude") String latitude, + @RequestParam(name = "longitude") String longitude, @RequestParam("complaint_no") String complaint_no) { + + boolean locationStatus = false; + + Map response = new HashMap<>(); + + if (!latitude.isEmpty() && !longitude.isEmpty() && latitude != null && longitude != null) { + locationStatus = potholeService.checkLocation(latitude, longitude); + } + + if (locationStatus) { + response.put("status", true); + response.put("message", "Location Matched"); + return ResponseEntity.ok(response); + } + + response.put("status", false); + response.put("message", "Location Issue"); + response.put("description", "Please go to nearest location"); + return ResponseEntity.ok(response); + + } + + // report related api + + // zone wise AE pending and completed + + @GetMapping("/ae-zone-wise") + public ResponseEntity> getZoneWiseAEReport( + @RequestParam("fromDate") String fromDate, + @RequestParam("toDate") String toDate, + @RequestParam(required = false, name = "damage_type") String damage_type) { + + List> report = potholeService.getZoneWiseAEReport(fromDate, toDate, damage_type); + + + Map response = new HashMap<>(); + if (report.isEmpty()) { + response.put("status", false); + response.put("message", "No data found"); + response.put("data", Collections.emptyList()); + } else { + response.put("status", true); + response.put("message", "Data found"); + response.put("data", report); + } + + return ResponseEntity.ok(response); + + } + + + @GetMapping("/ae-ward-wise") + public ResponseEntity> getWardWiseAEReport( + @RequestParam("fromDate") String fromDate, + @RequestParam("toDate") String toDate, + @RequestParam("zone") String zone, + @RequestParam(required = false, name = "damage_type") String damage_type) { + + List> report = potholeService.getWardWiseAEReport(fromDate, toDate, zone, damage_type); + Map response = new HashMap<>(); + if (report.isEmpty()) { + response.put("status", false); + response.put("message", "No data found"); + response.put("data", Collections.emptyList()); + } else { + response.put("status", true); + response.put("message", "Data found"); + response.put("data", report); + } + + return ResponseEntity.ok(response); + + } + + + // report api for zone wise Vendor pending and completed + + + @GetMapping("/vendor-zone-wise") + public ResponseEntity> getZoneVendorWiseReport( + @RequestParam("fromDate") String fromDate, + @RequestParam("toDate") String toDate, + @RequestParam(required = false, name = "damage_type") String damage_type) { + + List> report = potholeService.getZoneWiseVendorReport(fromDate, toDate, damage_type); + Map response = new HashMap<>(); + if (report.isEmpty()) { + response.put("status", false); + response.put("message", "No data found"); + response.put("data", Collections.emptyList()); + } else { + response.put("status", true); + response.put("message", "Data found"); + response.put("data", report); + } + + return ResponseEntity.ok(response); + } + + + @GetMapping("/vendor-ward-wise") + public ResponseEntity> getWardWiseVendorReport( + @RequestParam("fromDate") String fromDate, + @RequestParam("toDate") String toDate, + @RequestParam("zone") String zone, + @RequestParam(required = false, name = "damage_type") String damage_type) { + + List> report = potholeService.getWardWiseVendorReport(fromDate, toDate, zone, damage_type); + Map response = new HashMap<>(); + if (report.isEmpty()) { + response.put("status", false); + response.put("message", "No data found"); + response.put("data", Collections.emptyList()); + } else { + response.put("status", true); + response.put("message", "Data found"); + response.put("data", report); + } + + return ResponseEntity.ok(response); + } + + + @GetMapping("/getdetailsbycomplaintno") + public ResponseEntity> getDetailsByComplaintNo(@RequestParam("complaintNo") String complaintNo) { + + List> result = potholeService.getDetailsByComplaintNo(complaintNo); + + Map response = new HashMap<>(); + if (result.isEmpty()) { + response.put("status", false); + response.put("message", "No data found"); + response.put("data", Collections.emptyList()); + } else { + response.put("status", true); + response.put("message", "Data found"); + response.put("data", result); + } + + return ResponseEntity.ok(response); + + } + + + // get the details by between date,zone and ward + @GetMapping("/getcomplaintdetails") + public ResponseEntity> getComplaintDetails( + + @RequestParam("fromDate") String fromDate, + @RequestParam("toDate") String toDate, + @RequestParam("zone") String zone, + @RequestParam("ward") String ward, + @RequestParam("streetId") String streetId, + @RequestParam(required = false, name = "damage_type") String damage_type, + @RequestParam(required = false, name = "status") String status + ) { + + List> result = potholeService.getAllComplaintNo(fromDate, toDate, zone, ward, streetId, damage_type, status); + + Map response = new HashMap<>(); + if (result.isEmpty()) { + response.put("status", false); + response.put("message", "No data found"); + response.put("data", Collections.emptyList()); + } else { + response.put("status", true); + response.put("message", "Data found"); + response.put("data", result); + } + + return ResponseEntity.ok(response); + + } + + @GetMapping("/getstreetdetails-ae") + public ResponseEntity> getStreetDetails( + + @RequestParam("fromDate") String fromDate, + @RequestParam("toDate") String toDate, + @RequestParam("zone") String zone, + @RequestParam("ward") String ward, + @RequestParam(required = false, name = "damage_type") String damage_type) { + + List> result = potholeService.getStreetDetailsAE(fromDate, toDate, zone, ward, damage_type); + + Map response = new HashMap<>(); + if (result.isEmpty()) { + response.put("status", false); + response.put("message", "No data found"); + response.put("data", Collections.emptyList()); + } else { + response.put("status", true); + response.put("message", "Data found"); + response.put("data", result); + } + + return ResponseEntity.ok(response); + + } + + @GetMapping("/getstreetdetails-vendor") + public ResponseEntity> getStreetDetailsVendor( + @RequestParam("fromDate") String fromDate, + @RequestParam("toDate") String toDate, + @RequestParam("zone") String zone, + @RequestParam("ward") String ward, + @RequestParam(required = false, name = "damage_type") String damage_type) { + + List> result = potholeService.getStreetDetailsVE(fromDate, toDate, zone, ward, damage_type); + + Map response = new HashMap<>(); + if (result.isEmpty()) { + response.put("status", false); + response.put("message", "No data found"); + response.put("data", Collections.emptyList()); + } else { + response.put("status", true); + response.put("message", "Data found"); + response.put("data", result); + } + + return ResponseEntity.ok(response); + + } + + // to save user complaints - new API + + @PostMapping("/save-user-complaint") + public ResponseEntity> saveUserComplaints( + @RequestParam("zone") String zone, + @RequestParam("ward") String ward, + @RequestParam(required = false, name = "latitude") String latitude, + @RequestParam(required = false, name = "longitude") String longitude, + @RequestParam(required = false, name = "length") String length, + @RequestParam(required = false, name = "width") String width, + @RequestParam(required = false, name = "area") String area, + @RequestParam("case_id") String caseId, + @RequestParam("street_id") String streetId, + @RequestParam("street_name") String streetName, + @RequestParam("status_id") String statusId, + @RequestParam(required = true, name = "complaint_photo") MultipartFile complaintPhoto, + @RequestParam(required = false, name = "user_length") String userLength, + @RequestParam(required = false, name = "user_width") String userWidth, + @RequestParam(required = false, name = "user_height") String userHeight, + @RequestParam("risk_level") String riskLevel) { + + // File upload paths + String complaintPhotoPath = (complaintPhoto != null) ? + potholeService.fileUpload(complaintPhoto, "user_complaint_photo") : ""; + + // Save to DB + String saveStatus = potholeService.saveUserComplaintDetails( + zone, ward, latitude, longitude, length, width, area, streetId, + streetName, statusId, complaintPhotoPath, caseId, userLength, userWidth, userHeight, riskLevel); + + Map response = new HashMap<>(); + if (saveStatus == null || saveStatus.isEmpty() || saveStatus.equals("error")) { + response.put("status", false); + response.put("message", "failed"); + response.put("description", "Failed to save the details"); + return ResponseEntity.ok(response); + } else if (saveStatus.equals("duplicate")) { + response.put("status", false); + response.put("message", "failed"); + response.put("description", "Complaints already exist"); + return ResponseEntity.ok(response); + } + + response.put("status", true); + response.put("message", "success"); + response.put("description", "Details were saved successfully"); + return ResponseEntity.ok(response); + } + + // get Pending user request for Approval + @GetMapping("/getPendingApprovalList") + public ResponseEntity> getPendingUserRequest(@RequestParam String loginId, + @RequestParam(required = false, name="fromDate") String fromDate, + @RequestParam(required = false, name="toDate") String toDate){ + + List> result = potholeService.getPendingUserRequest(loginId, fromDate, toDate); + + Map response = new HashMap<>(); + if (result.isEmpty()) { + response.put("status", false); + response.put("message", "No data found"); + response.put("data", Collections.emptyList()); + } else { + response.put("status", true); + response.put("message", "Data found"); + response.put("data", result); + } + + return ResponseEntity.ok(response); + } + + // save AE approval of pending user request + @PostMapping("/approveUserRequest") + public ResponseEntity> approveUserRequest(@RequestParam String loginId, @RequestParam String complaintNo, + @RequestParam(required = false, name="remarks") String remarks, + @RequestParam String status, @RequestParam String locationStatus){ + + Map result = potholeService.approveUserRequest(loginId, complaintNo, remarks, status, locationStatus); + + Map response = new HashMap<>(); + if (result.isEmpty()) { + response.put("status", false); + response.put("message", "No data found"); + response.put("data", Collections.emptyList()); + } else { + response.put("status", true); + response.put("message", "Data found"); + response.put("data", result); + } + + return ResponseEntity.ok(response); + } +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccpothole/controller/package-info.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccpothole/controller/package-info.java new file mode 100644 index 0000000..26a6dda --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccpothole/controller/package-info.java @@ -0,0 +1 @@ +package in.gov.chennaicorporation.mobileservice.gccpothole.controller; \ No newline at end of file diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccpothole/package-info.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccpothole/package-info.java new file mode 100644 index 0000000..fd486be --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccpothole/package-info.java @@ -0,0 +1 @@ +package in.gov.chennaicorporation.mobileservice.gccpothole; \ No newline at end of file diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccpothole/service/PotholeService.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccpothole/service/PotholeService.java new file mode 100644 index 0000000..1f6bd36 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccpothole/service/PotholeService.java @@ -0,0 +1,1031 @@ +package in.gov.chennaicorporation.mobileservice.gccpothole.service; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.SecureRandom; +import java.sql.PreparedStatement; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; + +import javax.imageio.ImageIO; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.stream.ImageOutputStream; +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.core.env.Environment; +import org.springframework.http.ResponseEntity; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import in.gov.chennaicorporation.mobileservice.gccactivity.service.DateTimeUtil; + +@Service +public class PotholeService { + + + @Autowired + private JdbcTemplate jdbcPotHoleTemplate; + + private final Environment environment; + + private String fileBaseUrl; + + private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + + private static final int STRING_LENGTH = 15; + + private static final Random RANDOM = new SecureRandom(); + + + @Autowired + public void setDataSource(@Qualifier("mysqlGccPotHoleDataSource") DataSource potHoleDataSource) { + this.jdbcPotHoleTemplate = new JdbcTemplate(potHoleDataSource); + } + + + public PotholeService(Environment environment) { + this.environment = environment; + this.fileBaseUrl = environment.getProperty("fileBaseUrl"); + } + + public static String generateRandomString() { + StringBuilder result = new StringBuilder(STRING_LENGTH); + for (int i = 0; i < STRING_LENGTH; i++) { + result.append(CHARACTERS.charAt(RANDOM.nextInt(CHARACTERS.length()))); + } + return result.toString(); + } + + + private byte[] compressImage(BufferedImage image, float quality) throws IOException { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(byteArrayOutputStream); + + ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next(); + writer.setOutput(imageOutputStream); + + ImageWriteParam param = writer.getDefaultWriteParam(); + if (param.canWriteCompressed()) { + param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); + param.setCompressionQuality(quality); + } + + writer.write(null, new javax.imageio.IIOImage(image, null, null), param); + + writer.dispose(); + imageOutputStream.close(); + + return byteArrayOutputStream.toByteArray(); + } + + public String fileUpload(MultipartFile file, String name) { + + // Set the file path where you want to save it + String uploadDirectory = environment.getProperty("file.upload.directory"); + String serviceFolderName = environment.getProperty("pothole_foldername"); + var year = DateTimeUtil.getCurrentYear(); + var month = DateTimeUtil.getCurrentMonth(); + + uploadDirectory = uploadDirectory + serviceFolderName + year + "/" + month; + + try { + // Create directory if it doesn't exist + Path directoryPath = Paths.get(uploadDirectory); + if (!Files.exists(directoryPath)) { + Files.createDirectories(directoryPath); + } + + // Datetime string + String datetimetxt = DateTimeUtil.getCurrentDateTime(); + // File name + String fileName = name + "_" + datetimetxt + "_" + file.getOriginalFilename(); + fileName = fileName.replaceAll("\\s+", ""); // Remove space on filename + + String filePath = uploadDirectory + "/" + fileName; + + String filepath_txt = "/" + serviceFolderName + year + "/" + month + "/" + fileName; + + // Create a new Path object + Path path = Paths.get(filePath); + + // Get the bytes of the file + byte[] bytes = file.getBytes(); + + // Compress the image + BufferedImage image = ImageIO.read(new ByteArrayInputStream(bytes)); + byte[] compressedBytes = compressImage(image, 0.5f); // Compress with 50% quality + + // Write the bytes to the file + Files.write(path, compressedBytes); + + System.out.println(filePath); + return filepath_txt; + + } catch (IOException e) { + e.printStackTrace(); + return "Failed to save file " + file.getOriginalFilename(); + } + } + + public String saveComplaintDetails(String zone, String ward, String latitudeStr, String longitudeStr, String length, + String width, String area, String streetId, String streetName, String statusId, + String complaintPhotoPath, String loginId, String caseId, String userLength, String userWidth, + String userHeight, String riskLevel, String damage_type) { + + double latitude = Double.parseDouble(latitudeStr); + double longitude = Double.parseDouble(longitudeStr); + /* + String checkSql = "SELECT count(*) FROM pothole_complaint_details pcd " + + "left join status_master sm on pcd.status_id = sm.id " + + "WHERE pcd.street_id =? and sm.status!='Completed' and (6371008.8 * ACOS(ROUND(COS(RADIANS(?)) * COS(RADIANS(pcd.latitude)) * COS(RADIANS(pcd.longitude) - RADIANS(?)) + SIN(RADIANS(?)) * SIN(RADIANS(pcd.latitude))))) < 3"; + */ + String checkSql = "SELECT count(*) FROM pothole_complaint_details pcd " + + "LEFT JOIN status_master sm ON pcd.status_id = sm.id " + + "WHERE pcd.street_id = ? " + + "AND sm.status != 'Completed' " + + "AND (6371008.8 * ACOS(" + + "COS(RADIANS(?)) * COS(RADIANS(pcd.latitude)) * " + + "COS(RADIANS(pcd.longitude) - RADIANS(?)) + " + + "SIN(RADIANS(?)) * SIN(RADIANS(pcd.latitude))" + + ")) < 3"; + + Integer count = jdbcPotHoleTemplate.queryForObject(checkSql, new Object[]{streetId, latitude, longitude, latitude}, Integer.class); + + if (count != null && count > 0) { + return "duplicate"; // ✅ Return "duplicate" if at least one match found + } + + + String sql = "INSERT INTO pothole_complaint_details (" + + "zone, ward, latitude,longitude, length, width, area, " + + "street_id, street_name,status_id, login_id,case_id,user_length,user_width,user_height, risk_level,damage_type)" + + " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; + + KeyHolder keyHolder = new GeneratedKeyHolder(); + + try { + int result = jdbcPotHoleTemplate.update(connection -> { + PreparedStatement ps = connection.prepareStatement(sql, new String[]{"id"}); + ps.setString(1, zone); + ps.setString(2, ward); + ps.setString(3, latitudeStr); + ps.setString(4, longitudeStr); + ps.setString(5, length); + ps.setString(6, width); + ps.setString(7, area); + ps.setString(8, streetId); + ps.setString(9, streetName); + ps.setString(10, statusId); + //ps.setString(11, complaintPhotoPath); + ps.setString(11, loginId); + ps.setString(12, caseId); + ps.setString(13, userLength); + ps.setString(14, userWidth); + ps.setString(15, userHeight); + ps.setString(16, riskLevel); + ps.setString(17, damage_type); + return ps; + }, keyHolder); + + + //return keyHolder.getKey().intValue(); + if (result > 0) { + int generatedId = keyHolder.getKey().intValue(); + String prefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); + String refId = prefix + generatedId; + // update vendor table with reference ID + String updateVendorSql = "UPDATE pothole_complaint_details SET complaint_no = ? WHERE id = ?"; + + jdbcPotHoleTemplate.update(updateVendorSql, refId, generatedId); + + + // ✅ insert image path into image table + if (complaintPhotoPath != null && !complaintPhotoPath.isBlank()) { + String insertImageSql = "INSERT INTO complaint_images (complaint_no, complaint_image_url,image_flag) VALUES (?, ?,? )"; + jdbcPotHoleTemplate.update(insertImageSql, refId, complaintPhotoPath, "before"); + } + return refId; + } + //return "error"; + } catch (Exception e) { + e.printStackTrace(); + } + return "error"; + } + + + //To fetch all status + public List> getAllStatus() { + String sql = "SELECT id, status FROM status_master WHERE is_active = 1 AND is_delete = 0 "; + return jdbcPotHoleTemplate.queryForList(sql); + } + + + //kani akka +// public List> getComplaintsByWard(String aeUserId) { +// // Step 1: Get zone and ward +// String Sql = "SELECT zone, ward FROM ae_login WHERE ae_userid = ?"; +// Map vendorData = jdbcPotHoleTemplate.queryForMap(Sql, aeUserId); +// +// +// // String zone = String.valueOf(vendorData.get("zone")); +// String ward = String.valueOf(vendorData.get("ward")); +// +// // Step 2: Get complaints using zone and ward +// String complaintsql = "SELECT cd.* ,DATE_FORMAT(cd.cdate, '%d-%m-%Y') as complaint_date,sm.status," +// + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files',ci.complaint_image_url) as complaint_image_url " +// + " FROM pothole_complaint_details cd " +// + " Left JOIN complaint_images ci ON ci.complaint_no = cd.complaint_no " +// + " Left JOIN status_master sm ON sm.id = cd.status_id " +// + " WHERE cd.ward = ? AND cd.status_id IN (2,4)"; +// +// return jdbcPotHoleTemplate.queryForList(complaintsql, ward); +// } + + + //yogi + + public List> getComplaintsByWard(String aeUserId) { + String sql = "SELECT zone, ward FROM gcc_penalty_hoardings.`hoading_user_list` WHERE userid = ? AND type='ae'"; + List> userList = jdbcPotHoleTemplate.queryForList(sql, aeUserId); + + if (userList.isEmpty()) { + // You can return an empty list or throw a custom exception + return Collections.emptyList(); // or handle as needed + } + + Map vendorData = userList.get(0); + String ward = String.valueOf(vendorData.get("ward")); + + String complaintSql = + "SELECT cd.*, " + + " DATE_FORMAT(cd.cdate, '%d-%m-%Y') AS complaint_date, " + + " sm.status, " + + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files', ci.complaint_image_url) AS complaint_image_url, " + + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files', vi.complaint_image_url) AS vendor_image_url " + + "FROM pothole_complaint_details cd " + + "LEFT JOIN status_master sm ON sm.id = cd.status_id " + + "LEFT JOIN ( " + + " SELECT complaint_no, MIN(complaint_image_url) AS complaint_image_url " + + " FROM complaint_images " + + " GROUP BY complaint_no " + + ") ci ON ci.complaint_no = cd.complaint_no " + + "LEFT JOIN ( " + + " SELECT complaint_no, MIN(complaint_image_url) AS complaint_image_url " + + " FROM complaint_images " + + " WHERE image_flag = 'vendor' " + + " GROUP BY complaint_no " + + ") vi ON vi.complaint_no = cd.complaint_no " + + "WHERE cd.ward = ? AND cd.status_id IN (1, 2, 4, 6)"; + + return jdbcPotHoleTemplate.queryForList(complaintSql, ward); + } + + // yogi modified + + public List> getComplaintsByVendorId(String vendorUserId) { + // Step 1: Get zone and ward + String vendorSql = "SELECT zone, ward FROM vendor_login WHERE vendor_userid = ?"; + List> vendorList = jdbcPotHoleTemplate.queryForList(vendorSql, vendorUserId); + + // If no vendor found, return empty list + if (vendorList.isEmpty()) { + return Collections.emptyList(); + } + + Map vendorData = vendorList.get(0); + String ward = String.valueOf(vendorData.get("ward")); + + // Step 2: Get complaints using ward + String complaintSql = "SELECT cd.*, DATE_FORMAT(cd.cdate, '%d-%m-%Y') AS complaint_date, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', ci.complaint_image_url) AS complaint_image_url, " + + "sm.status " + + "FROM pothole_complaint_details cd " + + "LEFT JOIN complaint_images ci ON ci.complaint_no = cd.complaint_no " + + "LEFT JOIN status_master sm ON sm.id = cd.status_id " + + "WHERE cd.ward = ? AND cd.status_id IN (1,3,7)"; + + return jdbcPotHoleTemplate.queryForList(complaintSql, ward); + } + + + public List> getFlatRequestList(String loginId) { + + String sql = "SELECT " + + " pcd.complaint_no, " + + " pcd.*, " + + " DATE_FORMAT(pcd.cdate, '%d-%m-%Y') as complaint_date, " + + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files', ci.complaint_image_url) AS complaint_image_url, " + + " ci.image_flag, " + + " sm.status " + + "FROM pothole_complaint_details pcd " + + "JOIN complaint_images ci ON pcd.complaint_no = ci.complaint_no " + + "LEFT JOIN status_master sm ON pcd.status_id = sm.id " + + "WHERE pcd.login_id = ?"; + + return jdbcPotHoleTemplate.queryForList(sql, loginId); + } + + + public List> getRequestList(String loginId) { + List> flatList = getFlatRequestList(loginId); + + Map> groupedMap = new LinkedHashMap<>(); + + for (Map row : flatList) { + String complaintNo = (String) row.get("complaint_no"); + String imageFlag = (String) row.get("image_flag"); + String imageUrl = (String) row.get("complaint_image_url"); + + Map existing = groupedMap.get(complaintNo); + + if (existing == null) { + // Initialize map with all complaint fields except image fields + Map base = new LinkedHashMap<>(); + for (Map.Entry entry : row.entrySet()) { + String key = entry.getKey(); + if (!key.equals("complaint_image_url") && !key.equals("image_flag")) { + base.put(key, entry.getValue()); + } + } + + // Always add image fields with null (default) + base.put("before_image_url", null); + base.put("vendor_image_url", null); + base.put("reopen_image_url", null); + base.put("rectified_image_url", null); + base.put("completed_image_url", null); + + groupedMap.put(complaintNo, base); + existing = base; + } + + // Conditionally add image URL to the correct field + if ("Before".equalsIgnoreCase(imageFlag)) { + existing.put("before_image_url", imageUrl); + } else if ("Vendor".equalsIgnoreCase(imageFlag)) { + existing.put("vendor_image_url", imageUrl); + } else if ("Reopen".equalsIgnoreCase(imageFlag)) { + existing.put("reopen_image_url", imageUrl); + } else if ("Rectified".equalsIgnoreCase(imageFlag)) { + existing.put("rectified_image_url", imageUrl); + } else if ("Completed".equalsIgnoreCase(imageFlag)) { + existing.put("completed_image_url", imageUrl); + } + } + + return new ArrayList<>(groupedMap.values()); + } + + + public boolean checkLocation(String latitude, String longitude) { + String sql = "select count(*) from pothole_complaint_details pcd " + + "where ((6371008.8 * acos(ROUND(cos(radians(?)) * cos(radians(pcd.latitude)) * cos(radians(pcd.longitude) - radians(?)) +" + + "sin(radians(?)) * sin(radians(pcd.latitude)), 9))) )< 3 "; + + int count = jdbcPotHoleTemplate.queryForObject(sql, Integer.class, Double.parseDouble(latitude), Double.parseDouble(longitude), Double.parseDouble(latitude)); + + return count > 0; + } + + public String updateComplaintbyVendor(String statusId, + String loginId, + LocalDateTime updatedDate, + String vendorLength, + String vendorWidth, + String vendorHeight, + String vendorPhotoPath, + String aeLength, + String aeWidth, + String aeHeight, + String complaint_no) { + String status = insertIntoHistory(complaint_no); + //System.err.println("updateComplaintbyVendor - status : "+ status); + int count = 0; + try { + if ("Success".equalsIgnoreCase(status.trim())) { + + System.err.println("Inside Success Attempting update with: " + + "statusId=" + statusId + ", loginId=" + loginId + ", updatedDate=" + updatedDate + + ", vendorLength=" + vendorLength + ", vendorWidth=" + vendorWidth + ", vendorHeight=" + vendorHeight + + ", complaint_no=" + complaint_no); + + if ("2".equalsIgnoreCase(statusId.trim()) || "4".equalsIgnoreCase(statusId.trim())) { + String updateSql = "update pothole_complaint_details set status_id =?, updated_login_id =?, updated_date =? , vendor_length = ? , vendor_width = ? , vendor_height = ? where complaint_no = ? "; + //System.err.println("Vendor Executing SQL: " + updateSql); + //System.err.printf("Params: [%s, %s, %s, %s, %s, %s, %s]%n", statusId, loginId, updatedDate, vendorLength, vendorWidth, vendorHeight, complaint_no); + count = jdbcPotHoleTemplate.update(updateSql, statusId, loginId, updatedDate, vendorLength, vendorWidth, vendorHeight, complaint_no); + } else if ("3".equalsIgnoreCase(statusId.trim()) || "5".equalsIgnoreCase(statusId.trim())) { + String updateSql = "update pothole_complaint_details set status_id =?, updated_login_id =?, updated_date =? , ae_length = ? , ae_width = ? , ae_height = ? where complaint_no = ? "; + // System.err.println("AE Executing SQL: " + updateSql); + //System.err.printf("Params: [%s, %s, %s, %s, %s, %s, %s]%n", statusId, loginId, updatedDate, aeLength, aeWidth, aeHeight, complaint_no); + count = jdbcPotHoleTemplate.update(updateSql, statusId, loginId, updatedDate, aeLength, aeWidth, aeHeight, complaint_no); + } + + if (count > 0) { + + if ("2".equalsIgnoreCase(statusId.trim())) { + + // ✅ insert image path into image table + if (vendorPhotoPath != null && !vendorPhotoPath.isBlank()) { + String insertImageSql = "INSERT INTO complaint_images (complaint_no, complaint_image_url,image_flag) VALUES (?, ?,? )"; + jdbcPotHoleTemplate.update(insertImageSql, complaint_no, vendorPhotoPath, "vendor"); + } + + } else if ("4".equalsIgnoreCase(statusId.trim())) { + + if (vendorPhotoPath != null && !vendorPhotoPath.isBlank()) { + String insertImageSql = "INSERT INTO complaint_images (complaint_no, complaint_image_url,image_flag) VALUES (?, ?,? )"; + jdbcPotHoleTemplate.update(insertImageSql, complaint_no, vendorPhotoPath, "rectified"); + } + + } else if ("3".equalsIgnoreCase(statusId.trim())) { + + if (vendorPhotoPath != null && !vendorPhotoPath.isBlank()) { + String insertImageSql = "INSERT INTO complaint_images (complaint_no, complaint_image_url,image_flag) VALUES (?, ?,? )"; + jdbcPotHoleTemplate.update(insertImageSql, complaint_no, vendorPhotoPath, "reopen"); + } + } else if ("5".equalsIgnoreCase(statusId.trim())) { + + if (vendorPhotoPath != null && !vendorPhotoPath.isBlank()) { + String insertImageSql = "INSERT INTO complaint_images (complaint_no, complaint_image_url,image_flag) VALUES (?, ?,? )"; + //System.err.println("complaint_images Executing SQL: " + insertImageSql); + //System.err.printf("Params: [%s, %s, %s]%n", complaint_no, vendorPhotoPath, "completed"); + jdbcPotHoleTemplate.update(insertImageSql, complaint_no, vendorPhotoPath, "completed"); + } + + } else { + return "Invalid Status Id"; + } + + return "Success"; + } + } + } catch (Exception e) { + //System.err.println("Error inserting into Update: " + e.getMessage()); + e.printStackTrace(); // Shows full stack trace + //return "Failed: " + e.getMessage(); + } + /* + System.err.println("Attempting update with: " + + "statusId=" + statusId + ", loginId=" + loginId + ", updatedDate=" + updatedDate + + ", vendorLength=" + vendorLength + ", vendorWidth=" + vendorWidth + ", vendorHeight=" + vendorHeight + + ", complaint_no=" + complaint_no); + */ + return "Failed to save the data"; + } + + private String insertIntoHistory(String complaintNo) { + if (complaintNo == null || complaintNo.trim().isEmpty()) { + return "Complaint No is Empty"; + } + + try { + String selectSql = "SELECT * FROM pothole_complaint_details WHERE complaint_no = ? LIMIT 1"; + Map complaintDetails = jdbcPotHoleTemplate.queryForMap(selectSql, complaintNo); + + if (complaintDetails != null && !complaintDetails.isEmpty()) { + String insertSql = "INSERT INTO pothole_complaint_details_history (" + + "complaint_no, zone, ward, latitude, longitude, length, width, area, street_id, street_name, status_id, cdate, updated_date, remarks, " + + "login_id, case_id, updated_login_id, user_length, user_width, user_height, vendor_length, vendor_width, vendor_height, ae_length, ae_width, ae_height, risk_level, " + + "request_by, approved_by, approved_date, approved_remarks, location_status) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + jdbcPotHoleTemplate.update(insertSql, + complaintDetails.get("complaint_no"), + complaintDetails.get("zone"), + complaintDetails.get("ward"), + complaintDetails.get("latitude"), + complaintDetails.get("longitude"), + complaintDetails.get("length"), + complaintDetails.get("width"), + complaintDetails.get("area"), + complaintDetails.get("street_id"), + complaintDetails.get("street_name"), + complaintDetails.get("status_id"), + complaintDetails.get("cdate"), + complaintDetails.get("updated_date"), + complaintDetails.get("remarks"), + complaintDetails.get("login_id"), + complaintDetails.get("case_id"), + complaintDetails.get("updated_login_id"), + complaintDetails.get("user_length"), + complaintDetails.get("user_width"), + complaintDetails.get("user_height"), + complaintDetails.get("vendor_length"), + complaintDetails.get("vendor_width"), + complaintDetails.get("vendor_height"), + complaintDetails.get("ae_length"), + complaintDetails.get("ae_width"), + complaintDetails.get("ae_height"), + complaintDetails.get("risk_level"), + complaintDetails.get("request_by"), + complaintDetails.get("approved_by"), + complaintDetails.get("approved_date"), + complaintDetails.get("approved_remarks"), + complaintDetails.get("location_status") + ); + + return "Success"; + } else { + return "Complaint Details Not Found: " + complaintNo; + } + } catch (Exception e) { + System.err.println("Error inserting into history: " + e.getMessage()); + return "Failed: " + e.getMessage(); + } + } + + public List> getZoneWiseAEReport(String fromDate, String toDate, String damage_type) { + + String formattedFrom = formatFromDate(fromDate); + String formattedTo = formatToDate(toDate); + String where=""; + if(damage_type!=null) + { + where=" AND pcd.`damage_type`='"+damage_type+"' "; + } + String sql = "SELECT pcd.zone, " + + "COUNT(pcd.complaint_no) AS total_mapped, " + + "SUM(CASE WHEN pcd.status_id IN (1, 2, 4, 6) THEN 1 ELSE 0 END) AS ae_pending, " + + "SUM(CASE WHEN pcd.status_id = '5' THEN 1 ELSE 0 END) AS ae_completed " + + "FROM pothole_complaint_details pcd " + + "LEFT JOIN status_master st ON st.id = pcd.status_id " + + "WHERE DATE(pcd.cdate) BETWEEN ? AND ? " + where + + "GROUP BY pcd.zone " + + "ORDER BY pcd.zone "; + + return jdbcPotHoleTemplate.queryForList(sql, formattedFrom, formattedTo); + } + + + public List> getWardWiseAEReport(String fromDate, String toDate, String zone, String damage_type) { + + String formattedFrom = formatFromDate(fromDate); + String formattedTo = formatToDate(toDate); + String where=""; + if(damage_type!=null) + { + where=" AND pcd.`damage_type`='"+damage_type+"' "; + } + String sql = "SELECT " + + "pcd.zone,pcd.ward,count(pcd.complaint_no) AS total_mapped," + + "SUM(CASE WHEN pcd.status_id IN (1, 2, 4, 6) THEN 1 ELSE 0 END) AS ae_pending, " + + "SUM(CASE WHEN pcd.status_id = '5' THEN 1 ELSE 0 END) AS ae_completed " + + "FROM pothole_complaint_details pcd " + + "LEFT JOIN status_master st ON st.id = pcd.status_id " + + "WHERE DATE(pcd.cdate) BETWEEN ? AND ? AND pcd.zone= ? " + where + + "GROUP BY pcd.ward " + + "ORDER BY pcd.ward "; + + return jdbcPotHoleTemplate.queryForList(sql, formattedFrom, formattedTo, zone); + } + + public List> getZoneWiseVendorReport(String fromDate, String toDate, String damage_type) { + + String formattedFrom = formatFromDate(fromDate); + String formattedTo = formatToDate(toDate); + String where=""; + if(damage_type!=null) + { + where=" AND pcd.`damage_type`='"+damage_type+"' "; + } + String sql = "SELECT " + + "pcd.zone,count(pcd.complaint_no) AS total_mapped," + + "SUM(CASE WHEN pcd.status_id IN ('1','3') THEN 1 ELSE 0 END) AS vendor_pending," + + "SUM(CASE WHEN pcd.status_id IN ('2','4') THEN 1 ELSE 0 END) AS vendor_completed " + + "FROM pothole_complaint_details pcd " + + "LEFT JOIN status_master st ON st.id = pcd.status_id " + + "WHERE DATE(pcd.cdate) BETWEEN ? AND ? " + where + + "GROUP BY pcd.zone " + + "ORDER BY pcd.zone "; + + return jdbcPotHoleTemplate.queryForList(sql, formattedFrom, formattedTo); + } + + + public List> getWardWiseVendorReport(String fromDate, String toDate, String zone, String damage_type) { + + String formattedFrom = formatFromDate(fromDate); + String formattedTo = formatToDate(toDate); + String where=""; + if(damage_type!=null) + { + where=" AND pcd.`damage_type`='"+damage_type+"' "; + } + String sql = "SELECT " + + "pcd.zone,pcd.ward,count(pcd.complaint_no) AS total_mapped," + + "SUM(CASE WHEN pcd.status_id IN ('1','3') THEN 1 ELSE 0 END) AS vendor_pending," + + "SUM(CASE WHEN pcd.status_id IN ('2','4') THEN 1 ELSE 0 END) AS vendor_completed " + + "FROM pothole_complaint_details pcd " + + "LEFT JOIN status_master st ON st.id = pcd.status_id " + + "WHERE DATE(pcd.cdate) BETWEEN ? AND ? AND pcd.zone=? " + where + + "GROUP BY pcd.ward " + + "ORDER BY pcd.ward "; + + return jdbcPotHoleTemplate.queryForList(sql, formattedFrom, formattedTo, zone); + } + + + // get the details by complaint_no + + + public List> getComplaintList(String complaintNo) { + + String sql = "select pcd.complaint_no,pcd.zone,pcd.ward,pcd.latitude,pcd.longitude, " + + "pcd.street_id,pcd.street_name,pcd.case_id,pcd.user_length,pcd.user_width,pcd.user_height, " + + "pcd.vendor_length,pcd.vendor_width,pcd.vendor_height,pcd.ae_length,pcd.ae_width,pcd.ae_height, " + + "st.status, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', ci.complaint_image_url) AS complaint_image_url, " + + "ci.image_flag " + + "from pothole_complaint_details pcd " + + "LEFT JOIN complaint_images ci on ci.complaint_no=pcd.complaint_no " + + "LEFT JOIN status_master st on st.id=pcd.status_id " + + "WHERE pcd.complaint_no= ? "; + + return jdbcPotHoleTemplate.queryForList(sql, complaintNo); + } + + + public List> getDetailsByComplaintNo(String complaintNo) { + List> complaintList = getComplaintList(complaintNo); + + Map> groupedMap = new LinkedHashMap<>(); + + for (Map row : complaintList) { + String complaintnumber = (String) row.get("complaint_no"); + String imageFlag = (String) row.get("image_flag"); + String imageUrl = (String) row.get("complaint_image_url"); + + Map existing = groupedMap.get(complaintnumber); + + if (existing == null) { + // Initialize map with all complaint fields except image fields + Map base = new LinkedHashMap<>(); + for (Map.Entry entry : row.entrySet()) { + String key = entry.getKey(); + if (!key.equals("complaint_image_url") && !key.equals("image_flag")) { + base.put(key, entry.getValue()); + } + } + + // Always add image fields with null (default) + base.put("before_image_url", null); + base.put("vendor_image_url", null); + base.put("reopen_image_url", null); + base.put("rectified_image_url", null); + base.put("completed_image_url", null); + + groupedMap.put(complaintnumber, base); + existing = base; + } + + // Conditionally add image URL to the correct field + if ("Before".equalsIgnoreCase(imageFlag)) { + existing.put("before_image_url", imageUrl); + } else if ("Vendor".equalsIgnoreCase(imageFlag)) { + existing.put("vendor_image_url", imageUrl); + } else if ("Reopen".equalsIgnoreCase(imageFlag)) { + existing.put("reopen_image_url", imageUrl); + } else if ("Rectified".equalsIgnoreCase(imageFlag)) { + existing.put("rectified_image_url", imageUrl); + } else if ("Completed".equalsIgnoreCase(imageFlag)) { + existing.put("completed_image_url", imageUrl); + } + } + + return new ArrayList<>(groupedMap.values()); + } + + + // get the details by between date and zone,ward + + public List> getAllComplaints(String fromDate, String toDate, String zone, String ward, String streetId, String damage_type, String status) { + + String formattedFrom = formatFromDate(fromDate); + String formattedTo = formatToDate(toDate); + String where=""; + if(damage_type!=null) + { + where +=" AND pcd.`damage_type`='"+damage_type+"' "; + } + if(status!=null) + { + if (status.equalsIgnoreCase("pending")) { + where+=" AND pcd.status_id IN (1, 2, 4, 6) "; + } + if (status.equalsIgnoreCase("completed")) { + where+=" AND pcd.status_id IN (5) "; + } + } + + String sql = "select pcd.complaint_no,pcd.zone,pcd.ward,pcd.latitude,pcd.longitude, " + + "pcd.length,pcd.width,pcd.area, " + + "pcd.street_id,pcd.street_name,pcd.case_id,pcd.user_length,pcd.user_width,pcd.user_height, " + + "pcd.vendor_length,pcd.vendor_width,pcd.vendor_height,pcd.ae_length,pcd.ae_width,pcd.ae_height, " + + "st.status, date_format(pcd.cdate, '%d-%m-%Y') as createdDate, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', ci.complaint_image_url) AS complaint_image_url, " + + "ci.image_flag, date_format(ci.cdate, '%d-%m-%Y') as imgDate " + + "from pothole_complaint_details pcd " + + "LEFT JOIN complaint_images ci on ci.complaint_no=pcd.complaint_no " + + "LEFT JOIN status_master st on st.id=pcd.status_id " + + "WHERE DATE(pcd.cdate) BETWEEN ? AND ? AND pcd.zone = ? AND pcd.ward= ? and pcd.street_id = ? "+ where; + + return jdbcPotHoleTemplate.queryForList(sql, formattedFrom, formattedTo, zone, ward, streetId); + } + + + public List> getAllComplaintNo(String fromDate, String toDate, String zone, String ward, String streetId, String damage_type, String status) { + List> complaintList = getAllComplaints(fromDate, toDate, zone, ward, streetId, damage_type, status); + + Map> groupedMap = new LinkedHashMap<>(); + + for (Map row : complaintList) { + String complaintnumber = (String) row.get("complaint_no"); + String imageFlag = (String) row.get("image_flag"); + String imageUrl = (String) row.get("complaint_image_url"); + String imageDate = (String) row.get("imgDate"); + + Map existing = groupedMap.get(complaintnumber); + + if (existing == null) { + // Initialize map with all complaint fields except image fields + Map base = new LinkedHashMap<>(); + for (Map.Entry entry : row.entrySet()) { + String key = entry.getKey(); + if (!key.equals("complaint_image_url") && !key.equals("image_flag")) { + base.put(key, entry.getValue()); + } + } + + // Always add image fields with null (default) + base.put("before_image_url", null); + base.put("vendor_image_url", null); + base.put("reopen_image_url", null); + base.put("rectified_image_url", null); + base.put("completed_image_url", null); + + groupedMap.put(complaintnumber, base); + existing = base; + } + + // Conditionally add image URL to the correct field + if ("Before".equalsIgnoreCase(imageFlag)) { + existing.put("before_image_url", imageUrl); + } else if ("Vendor".equalsIgnoreCase(imageDate)) { + existing.put("vendor_image_url", imageUrl); + } else if ("Reopen".equalsIgnoreCase(imageFlag)) { + existing.put("reopen_image_url", imageUrl); + } else if ("Rectified".equalsIgnoreCase(imageFlag)) { + existing.put("rectified_image_url", imageUrl); + } else if ("Completed".equalsIgnoreCase(imageFlag)) { + existing.put("completed_image_url", imageUrl); + } + + if ("Vendor".equalsIgnoreCase(imageDate)) { + existing.put("vendor_completed_date", imageDate); + } else if ("Reopen".equalsIgnoreCase(imageDate)) { + existing.put("reopen_date", imageDate); + } else if ("Rectified".equalsIgnoreCase(imageDate)) { + existing.put("rectified_date", imageDate); + } else if ("Completed".equalsIgnoreCase(imageDate)) { + existing.put("completed_date", imageDate); + } + } + + return new ArrayList<>(groupedMap.values()); + } + + public String formatFromDate(String fromDATE) { + DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); + DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + LocalDate fromDate = LocalDate.parse(fromDATE, inputFormatter); + return fromDate.format(outputFormatter); + } + + public String formatToDate(String toDATE) { + DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); + DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + LocalDate toDate = LocalDate.parse(toDATE, inputFormatter); + return toDate.format(outputFormatter); + } + + public List> getStreetDetailsAE(String fromDate, String toDate, String zone, String ward, String damage_type) { + + String formattedFrom = formatFromDate(fromDate); + String formattedTo = formatToDate(toDate); + String where=""; + if(damage_type!=null) + { + where=" AND pcd.`damage_type`='"+damage_type+"' "; + } + String sql = "SELECT " + + "pcd.street_id, pcd.street_name, pcd.zone,pcd.ward, " + + "COUNT(*) AS total_complaints, " + + "SUM(CASE WHEN pcd.status_id IN (1, 2, 4, 6) THEN 1 ELSE 0 END) AS ae_pending, " + + "SUM(CASE WHEN pcd.status_id = '5' THEN 1 ELSE 0 END) AS ae_completed " + + "FROM pothole_complaint_details pcd " + + "WHERE DATE(pcd.cdate) BETWEEN ? AND ? AND pcd.zone = ? AND pcd.ward= ? " + where + + "GROUP BY pcd.street_id,pcd.zone,pcd.ward " + + "ORDER BY pcd.street_id "; + System.err.println(sql); + return jdbcPotHoleTemplate.queryForList(sql, formattedFrom, formattedTo, zone, ward); + } + + public List> getStreetDetailsVE(String fromDate, String toDate, String zone, String ward, String damage_type) { + + String formattedFrom = formatFromDate(fromDate); + String formattedTo = formatToDate(toDate); + String where=""; + if(damage_type!=null) + { + where=" AND pcd.`damage_type`='"+damage_type+"' "; + } + + String sql = "SELECT " + + "pcd.street_id, pcd.street_name, pcd.zone,pcd.ward," + + "COUNT(*) AS total_complaints, " + + "SUM(CASE WHEN pcd.status_id IN ('1','3') THEN 1 ELSE 0 END) AS vendor_pending," + + "SUM(CASE WHEN pcd.status_id IN ('2','4') THEN 1 ELSE 0 END) AS vendor_completed " + + "FROM pothole_complaint_details pcd " + + "WHERE DATE(pcd.cdate) BETWEEN ? AND ? AND pcd.zone = ? AND pcd.ward= ? " + where + + "GROUP BY pcd.street_id,pcd.zone,pcd.ward " + + "ORDER BY pcd.street_id "; + return jdbcPotHoleTemplate.queryForList(sql, formattedFrom, formattedTo, zone, ward); + } + + public String saveUserComplaintDetails(String zone, String ward, String latitude, String longitude, String length, + String width, String area, String streetId, String streetName, String statusId, + String complaintPhotoPath, String caseId, String userLength, String userWidth, + String userHeight, String riskLevel) { + + String checkSql = "SELECT count(*) FROM pothole_complaint_details pcd " + + "left join status_master sm on pcd.status_id = sm.id " + + "WHERE pcd.street_id =? and sm.status!='Completed' and (6371008.8 * ACOS(ROUND(COS(RADIANS(?)) * COS(RADIANS(pcd.latitude)) * COS(RADIANS(pcd.longitude) - RADIANS(?)) + SIN(RADIANS(?)) * SIN(RADIANS(pcd.latitude)), 9))) <50"; + + Integer count = jdbcPotHoleTemplate.queryForObject(checkSql, new Object[]{streetId, latitude, longitude, latitude}, Integer.class); + + if (count != null && count > 0) { + return "duplicate"; // ✅ Return "duplicate" if at least one match found + } + + + String sql = "INSERT INTO pothole_complaint_details (" + + "zone, ward, latitude,longitude, length, width, area, " + + "street_id, street_name,status_id, login_id,case_id,user_length,user_width,user_height, risk_level, request_by)" + + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?,?,?,?,?,?)"; + + KeyHolder keyHolder = new GeneratedKeyHolder(); + + try { + int result = jdbcPotHoleTemplate.update(connection -> { + PreparedStatement ps = connection.prepareStatement(sql, new String[]{"id"}); + ps.setString(1, zone); + ps.setString(2, ward); + ps.setString(3, latitude); + ps.setString(4, longitude); + ps.setString(5, length); + ps.setString(6, width); + ps.setString(7, area); + ps.setString(8, streetId); + ps.setString(9, streetName); + ps.setString(10, statusId); + //ps.setString(11, complaintPhotoPath); + ps.setInt(11, 000); + ps.setString(12, caseId); + ps.setString(13, userLength); + ps.setString(14, userWidth); + ps.setString(15, userHeight); + ps.setString(16, riskLevel); + ps.setString(17, "Others"); + + return ps; + }, keyHolder); + + + //return keyHolder.getKey().intValue(); + if (result > 0) { + int generatedId = keyHolder.getKey().intValue(); + String prefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); + String refId = prefix + generatedId; + // update vendor table with reference ID + String updateVendorSql = "UPDATE pothole_complaint_details SET complaint_no = ? WHERE id = ?"; + + jdbcPotHoleTemplate.update(updateVendorSql, refId, generatedId); + + + // ✅ insert image path into image table + if (complaintPhotoPath != null && !complaintPhotoPath.isBlank()) { + String insertImageSql = "INSERT INTO complaint_images (complaint_no, complaint_image_url,image_flag) VALUES (?, ?,? )"; + jdbcPotHoleTemplate.update(insertImageSql, refId, complaintPhotoPath, "before"); + } + return refId; + } + //return "error"; + } catch (Exception e) { + e.printStackTrace(); + } + return "error"; + } + + + public List> getPendingUserRequest(String loginId, String fromDate, String toDate) { + try { + String sql = "SELECT zone, ward FROM gcc_penalty_hoardings.`hoading_user_list` WHERE userid = ? AND type='ae'"; + List> aeList = jdbcPotHoleTemplate.queryForList(sql, loginId); + + if (aeList.isEmpty()) { + // You can return an empty list or throw a custom exception + return Collections.emptyList(); // or handle as needed + } + + Map vendorData = aeList.get(0); + String ward = String.valueOf(vendorData.get("ward")); + + StringBuilder sqlQuery = new StringBuilder(); + + sqlQuery = + new StringBuilder("SELECT cd.*, " + + " DATE_FORMAT(cd.cdate, '%d-%m-%Y') AS complaint_date, " + + " sm.status, " + + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files', ci.complaint_image_url) AS complaint_image_url, " + + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files', vi.complaint_image_url) AS vendor_image_url " + + "FROM pothole_complaint_details cd " + + "LEFT JOIN status_master sm ON sm.id = cd.status_id " + + "LEFT JOIN ( " + + " SELECT complaint_no, MIN(complaint_image_url) AS complaint_image_url " + + " FROM complaint_images " + + " GROUP BY complaint_no " + + ") ci ON ci.complaint_no = cd.complaint_no " + + "LEFT JOIN ( " + + " SELECT complaint_no, MIN(complaint_image_url) AS complaint_image_url " + + " FROM complaint_images " + + " WHERE image_flag = 'vendor' " + + " GROUP BY complaint_no " + + ") vi ON vi.complaint_no = cd.complaint_no " + + "WHERE cd.ward = ? AND cd.request_by ='Others' and status_id not in (7,8) "); + + List params = new ArrayList<>(); + params.add(ward); + + if (fromDate != null && !fromDate.trim().isEmpty() && + toDate != null && !toDate.trim().isEmpty()) { + sqlQuery.append(" AND DATE(cd.cdate) BETWEEN STR_TO_DATE(?, '%d-%m-%Y') AND STR_TO_DATE(?, '%d-%m-%Y') "); + params.add(fromDate); + params.add(toDate); + } + + return jdbcPotHoleTemplate.queryForList(sqlQuery.toString(), params.toArray()); + + } catch (Exception e) { + e.printStackTrace(); + return Collections.emptyList(); // or handle as needed + } + } + + public Map approveUserRequest(String loginId, String complaintNo, String remarks, String status, String locationStatus) { + + String history = insertIntoHistory(complaintNo); + + LocalDateTime now = LocalDateTime.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + String formattedDateTime = now.format(formatter); + + String updateSql = "UPDATE pothole_complaint_details " + + "SET approved_by = ?, approved_date = ?, approved_remarks = ?, status_id = ?, location_status=? " + + "WHERE complaint_no = ?"; + + List params = new ArrayList<>(); + params.add(loginId); + params.add(formattedDateTime); + params.add(remarks); + params.add(status); + params.add(locationStatus); + params.add(complaintNo); + + // Execute update + int result = jdbcPotHoleTemplate.update(updateSql, params.toArray()); + + if (result > 0) { + // Fetch and return updated row + String selectSql = "SELECT * FROM pothole_complaint_details WHERE complaint_no = ?"; + return jdbcPotHoleTemplate.queryForMap(selectSql, complaintNo); + } else { + return Collections.emptyMap(); // or throw an exception + } + } + +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccpothole/service/package-info.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccpothole/service/package-info.java new file mode 100644 index 0000000..e055fab --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccpothole/service/package-info.java @@ -0,0 +1 @@ +package in.gov.chennaicorporation.mobileservice.gccpothole.service; \ No newline at end of file diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccschools/controller/SchoolUserController.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccschools/controller/SchoolUserController.java index 9623e5c..d40e509 100644 --- a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccschools/controller/SchoolUserController.java +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccschools/controller/SchoolUserController.java @@ -107,6 +107,7 @@ public class SchoolUserController { return new ResponseEntity<>("Failed to retrieve feedback: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); } } + @GetMapping("/getSchools") public ResponseEntity getSchools( @RequestParam String latitude, diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccschools/service/SchoolUserActivity.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccschools/service/SchoolUserActivity.java index c7692d5..5cdefce 100644 --- a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccschools/service/SchoolUserActivity.java +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccschools/service/SchoolUserActivity.java @@ -347,9 +347,10 @@ public class SchoolUserActivity { ////////////////////////////////////////////////////////////////////// public List> getSchoolsByLocationAndType(String latitude, String longitude) { + //ac.school_type = 10 Cluster kitchen String sql = "SELECT ac.id, ac.school_name,school_type FROM school_details ac WHERE " + "((6371008.8 * acos(ROUND(cos(radians(?)) * cos(radians(ac.latitude)) * cos(radians(ac.longitude) - radians(?)) + sin(radians(?)) * sin(radians(ac.latitude)), 9))) < 500) " - + "GROUP BY ac.id, ac.school_name,ac.school_type "; + + " AND ac.school_type=10 GROUP BY ac.id, ac.school_name,ac.school_type "; // Use latitude, longitude, and schoolType as positional parameters return jdbcSchoolsTemplate.queryForList(sql, new Object[]{latitude, longitude, latitude}); diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccstreetvendor/controller/StreetVendorController.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccstreetvendor/controller/StreetVendorController.java index 2d143e9..61b2a27 100644 --- a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccstreetvendor/controller/StreetVendorController.java +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccstreetvendor/controller/StreetVendorController.java @@ -101,11 +101,15 @@ public class StreetVendorController { education_status,marital_status,no_of_fam_mem,are_fam_mem_invol_str_ven ); - if (saveStatus == null || saveStatus.isEmpty() || saveStatus.equals("error")) { + if (saveStatus == null || saveStatus.isEmpty() || saveStatus.equals("error") || saveStatus.equals("mobile_error")) { + String error_desc ="Failed to save the details"; + if(saveStatus.equals("mobile_error")) { + error_desc ="Duplicate mobile number. This mobile number is already registered."; + } return ResponseEntity.ok(Map.of( "status", false, "message", "failed", - "description", "Failed to save the details" + "description", error_desc ).toString()); } @@ -264,4 +268,11 @@ public class StreetVendorController { .of("status", true, "message", "success", "description", "Details were saved successfully").toString()); } + + @GetMapping("/getAllVendorDetails_l1") + public List> getAllVendorDetails_l1( + @RequestParam(value = "loginId", required = false) String loginid + ) { + return streetVendorService.getAllVendorDetails_l1(loginid); + } } diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccstreetvendor/service/StreetVendorService.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccstreetvendor/service/StreetVendorService.java index 6382091..54b01fd 100644 --- a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccstreetvendor/service/StreetVendorService.java +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/gccstreetvendor/service/StreetVendorService.java @@ -30,6 +30,9 @@ import java.sql.PreparedStatement; import java.sql.Statement; import java.time.LocalDate; import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Random; @@ -172,6 +175,7 @@ public class StreetVendorService { String aadharFrontPhotoPath, String aadharBackPhotoPath, int educationStatus, int maritalStatus, int noOfFamMem,boolean areAnyFamMemInvolStrVen) { + String sql = "INSERT INTO vendor_details (" + "name, f_h_name, gender, dob, social_category, diff_abled, mob_no, aadhar_no, " + "present_address, present_district, present_pincode, vending_address, vending_district, vending_pincode, " @@ -262,7 +266,8 @@ public class StreetVendorService { " LEFT JOIN vending_category_master vcm ON vd.vending_category=vcm.id " + " LEFT JOIN `education_master` em ON vd.education_status=em.id " + " LEFT JOIN `marital_status_master` msm ON vd.marital_status=msm.id " + - " WHERE vd.ward IN (?)"); + " WHERE vd.ward IN (?) " + + "AND vd.id NOT IN (SELECT vdid FROM vendor_approval_level_1)"); return jdbcStreetVendorTemplate.queryForList(query.toString(),ward); } @@ -293,7 +298,7 @@ public class StreetVendorService { String transaction_mode,String svanidhi_loan_amount, String status, String remarks, String vendor_space_path) { - String sql = "INSERT INTO vendor_approval (" + String sql = "INSERT INTO vendor_approval_level_1 (" + "vendor_type, latitude, longitude, vendor_id_card, vending_nature, vendor_timing_id, transaction_mode_id, swanidi_loan_amount, status, remarks, " + "vendor_space_photo, vdid, cby" + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; @@ -334,4 +339,96 @@ public class StreetVendorService { return "error"; } + + // To fetch street vendor details + @Transactional + public List> getAllVendorDetails_l1(String loginid) { + + String ward = getWardByLoginId(loginid, "li"); + + StringBuilder query = new StringBuilder( + "SELECT " + + " vd.id AS vendor_id, vd.name, vd.f_h_name, vd.gender, vd.zone, vd.ward, " + + " vd.dob, vd.mob_no, vd.vending_space, vd.pm_svanidhi_loan, vd.bank_acc_status, " + + " vd.diff_abled, scm.category_name, vcm.vending_category_name, " + + " em.education, msm.marital_status, vd.no_of_fam_mem, " + + " CASE WHEN vd.are_any_fam_mem_invol_str_ven = TRUE THEN 'Yes' ELSE 'No' END AS family_member_involved, " + + " CONCAT(vd.present_district, ', ', vd.present_pincode, ', ', vd.present_address) AS residental_address, " + + " CONCAT(vd.vending_district, ', ', vd.vending_pincode, ', ', vd.vending_address) AS business_address, " + + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files', vd.street_vendor_photo) AS street_vendor_photo, " + + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files', vd.aadhar_front_photo) AS aadhar_front_photo, " + + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files', vd.aadhar_back_photo) AS aadhar_back_photo, " + + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files', vd.ration_card_photo) AS ration_card_photo, " + + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files', vd.bank_passbook) AS bank_passbook, " + + " DATE_FORMAT(vd.cdate, '%d-%m-%Y') AS request_date, " + + + // Inline L1 fields + " l1.id AS l1_id, l1.vendor_space_photo, l1.vendor_type, l1.latitude AS l1_latitude, l1.longitude AS l1_longitude, " + + " l1.vendor_id_card, l1.vending_nature, l1.vendor_timing_id, l1.transaction_mode_id, l1.swanidi_loan_amount, " + + " l1.status AS l1_status, l1.remarks AS l1_remarks, l1.cby AS l1_cby, " + + " DATE_FORMAT(l1.cdate, '%d-%m-%Y %h:%i %p') AS l1_cdate, " + + " DATE_FORMAT(l1.updated_date, '%d-%m-%Y %h:%i %p') AS l1_updated_date " + + + "FROM vendor_details vd " + + "LEFT JOIN social_category_master scm ON vd.social_category = scm.id " + + "LEFT JOIN vending_category_master vcm ON vd.vending_category = vcm.id " + + "LEFT JOIN education_master em ON vd.education_status = em.id " + + "LEFT JOIN marital_status_master msm ON vd.marital_status = msm.id " + + "LEFT JOIN vendor_approval_level_1 l1 ON vd.id = l1.vdid " + + "WHERE vd.ward IN (?) " + + "AND vd.id IN (SELECT vdid FROM vendor_approval_level_1) " + + "" + //"AND vd.id NOT IN (SELECT vdid FROM vendor_approval_level_2)" + ); + + List> flatList = jdbcStreetVendorTemplate.queryForList(query.toString(), ward); + List> finalList = new ArrayList<>(); + + for (Map row : flatList) { + Map vendor = new HashMap<>(row); + Map l1Data = new LinkedHashMap<>(); + + // Extract L1 data into sub-object + l1Data.put("id", row.get("l1_id")); + l1Data.put("vendor_space_photo", row.get("vendor_space_photo")); + l1Data.put("vendor_type", row.get("vendor_type")); + l1Data.put("latitude", row.get("l1_latitude")); + l1Data.put("longitude", row.get("l1_longitude")); + l1Data.put("vendor_id_card", row.get("vendor_id_card")); + l1Data.put("vending_nature", row.get("vending_nature")); + l1Data.put("vendor_timing_id", row.get("vendor_timing_id")); + l1Data.put("transaction_mode_id", row.get("transaction_mode_id")); + l1Data.put("swanidi_loan_amount", row.get("swanidi_loan_amount")); + l1Data.put("status", row.get("l1_status")); + l1Data.put("remarks", row.get("l1_remarks")); + l1Data.put("cby", row.get("l1_cby")); + l1Data.put("cdate", row.get("l1_cdate")); + l1Data.put("updated_date", row.get("l1_updated_date")); + + // Remove L1 fields from main object + // Explicitly remove L1 fields from parent row + row.remove("vendor_space_photo"); + row.remove("vendor_type"); + row.remove("l1_latitude"); + row.remove("l1_longitude"); + row.remove("vendor_id_card"); + row.remove("vending_nature"); + row.remove("vendor_timing_id"); + row.remove("transaction_mode_id"); + row.remove("swanidi_loan_amount"); + row.remove("l1_status"); + row.remove("l1_remarks"); + row.remove("l1_cby"); + row.remove("l1_cdate"); + row.remove("l1_updated_date"); + row.remove("l1_id"); + + // Add as sub-object + vendor.put("vendor_approval_level_1", l1Data); + + finalList.add(vendor); + } + + return finalList; + } } diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/penalty/controller/APICommonPrintController.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/penalty/controller/APICommonPrintController.java new file mode 100644 index 0000000..95e7b7d --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/penalty/controller/APICommonPrintController.java @@ -0,0 +1,29 @@ +package in.gov.chennaicorporation.mobileservice.penalty.controller; + +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import in.gov.chennaicorporation.mobileservice.penalty.service.PenaltyPrintService; + +@RequestMapping("/gccofficialapp/api/penalty") +@RestController("apiPenaltyprintRest") +public class APICommonPrintController { + @Autowired + private PenaltyPrintService penaltyPrintService; + + @GetMapping(value="/getSuccessList") + public List> getPenaltyTypes( + @RequestParam(value = "loginId", required = true) String loginId, + @RequestParam(value = "type", required = true) int type, + @RequestParam(value = "fromDate", required = true) String fromDate, + @RequestParam(value = "toDate", required = true) String toDate + ) { + return penaltyPrintService.getSuccessList(loginId, type,fromDate,toDate); + } +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/penalty/service/PenaltyPrintService.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/penalty/service/PenaltyPrintService.java new file mode 100644 index 0000000..dd3b488 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/penalty/service/PenaltyPrintService.java @@ -0,0 +1,204 @@ +package in.gov.chennaicorporation.mobileservice.penalty.service; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.core.env.Environment; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class PenaltyPrintService { + private JdbcTemplate jdbcPenaltyTemplate; + private final Environment environment; + private String fileBaseUrl; + + @Autowired + public void setDataSource(@Qualifier("mysqlActivityDataSource") DataSource penaltyDataSource) { + this.jdbcPenaltyTemplate = new JdbcTemplate(penaltyDataSource); + } + + @Autowired + public PenaltyPrintService(Environment environment) { + this.environment = environment; + this.fileBaseUrl=environment.getProperty("fileBaseUrl"); + } + + @Transactional + public List> getSuccessList(String loginId, int type, String fromDate, String toDate) { + List> result = new ArrayList<>(); + Map response = new HashMap<>(); + switch (type) { + case 1: + result = getPenalty_SuccessList(loginId, fromDate, toDate); + break; + case 2: + result = getCattle_SuccessList(loginId, fromDate, toDate); + break; + case 3: + result = getHoarding_SuccessList(loginId, fromDate, toDate); + break; + default: + // Optional: throw exception if type is invalid + //throw new IllegalArgumentException("Invalid type: " + type); + response.put("status", 400); + response.put("message", "Invalid type: " + type); + response.put("data", Collections.emptyList()); + return Collections.singletonList(response); + } + + response.put("status", 200); + response.put("message", "Fine Collected List"); + response.put("data", result); + + //return Collections.singletonList(response); + return result; + } + + @Transactional + public List> getPenalty_SuccessList(String loginId, String fromDate, String toDate) { + String sqlQuery = + "SELECT " + + " bt.id, " + + " bt.mid, " + + " bt.tid, " + + " bt.transactionResponseStatus, " + + " bt.txnCode, " + + " bt.txnId, " + + " bt.bankName, " + + " bt.batchNumber, " + + " bt.transactionAmount, " + + " bt.transactionTitle, " + + " bt.txnAID, " + + " bt.txnApprCode, " + + " bt.txnCardNo, " + + " bt.txnCardType, " + + " DATE_FORMAT(bt.txnDate, '%d-%m-%Y') AS txnDate, " + + " bt.txnInvoice, " + + " bt.txnMode, " + + " bt.txnRefNo, " + + " bt.txnTC, " + + " bt.txnTSI, " + + " bt.txnTVR, " + + " bt.txnTime, " + + " bt.branchname, " + + " bt.extraInfo, " + + " bt.extraInfo2, " + + " bt.extraInfo3, " + + " bt.file, " + + " bt.loginId, " + + " c3.violator_name, " + + " c3.violator_phone, " + + " c3.orderid, " + + " pc.name AS penaltyType " + + "FROM gcc_penalty_pos.bank_transactions bt " + + "LEFT JOIN gcc_penalty_pos.penalty_challan c3 ON bt.txnId = c3.orderid " + + "LEFT JOIN gcc_penalty_pos.penalty_category pc ON c3.category_id = pc.id " + + "WHERE bt.txnDate BETWEEN ? AND ? " + + "AND c3.challan_by = ? " + + "ORDER BY bt.txnDate DESC"; + + return jdbcPenaltyTemplate.queryForList(sqlQuery, fromDate, toDate, loginId); + } + + @Transactional + public List> getCattle_SuccessList(String loginId, String fromDate, String toDate) { + String sqlQuery = "SELECT " + + " bt.id, " + + " bt.mid, " + + " bt.tid, " + + " bt.transactionResponseStatus, " + + " bt.txnCode, " + + " bt.txnId, " + + " bt.bankName, " + + " bt.batchNumber, " + + " bt.transactionAmount, " + + " bt.transactionTitle, " + + " bt.txnAID, " + + " bt.txnApprCode, " + + " bt.txnCardNo, " + + " bt.txnCardType, " + + " DATE_FORMAT(bt.txnDate, '%d-%m-%Y') AS txnDate, " + + " bt.txnInvoice, " + + " bt.txnMode, " + + " bt.txnRefNo, " + + " bt.txnTC, " + + " bt.txnTSI, " + + " bt.txnTVR, " + + " bt.txnTime, " + + " bt.branchname, " + + " bt.extraInfo, " + + " bt.extraInfo2, " + + " bt.extraInfo3, " + + " bt.file, " + + " bt.loginId, " + + " c3.violator_name, " + + " c3.violator_phone, " + + " c3.orderid, " + + " 'Cattel Catch' AS penaltyType " + + "FROM gcc_penalty.bank_transactions bt " + + "LEFT JOIN gcc_penalty.cc_step3 c3 " + + " ON bt.txnId = c3.orderid " + + "WHERE bt.txnDate BETWEEN ? AND ? " + + "AND c3.challan_by = ? " + + "ORDER BY bt.txnDate DESC"; + //System.out.println("SQL : " + sqlQuery); + //List> result = jdbcPenaltyTemplate.queryForList(sqlQuery); + return jdbcPenaltyTemplate.queryForList(sqlQuery, fromDate, toDate, loginId); + } + + @Transactional + public List> getHoarding_SuccessList(String loginId, String fromDate, String toDate) { + String sqlQuery = "SELECT " + + " bt.id, " + + " bt.mid, " + + " bt.tid, " + + " bt.transactionResponseStatus, " + + " bt.txnCode, " + + " bt.txnId, " + + " bt.bankName, " + + " bt.batchNumber, " + + " bt.transactionAmount, " + + " bt.transactionTitle, " + + " bt.txnAID, " + + " bt.txnApprCode, " + + " bt.txnCardNo, " + + " bt.txnCardType, " + + " DATE_FORMAT(bt.txnDate, '%d-%m-%Y') AS txnDate, " + + " bt.txnInvoice, " + + " bt.txnMode, " + + " bt.txnRefNo, " + + " bt.txnTC, " + + " bt.txnTSI, " + + " bt.txnTVR, " + + " bt.txnTime, " + + " bt.branchname, " + + " bt.extraInfo, " + + " bt.extraInfo2, " + + " bt.extraInfo3, " + + " bt.file, " + + " bt.loginId, " + + " c3.agency_name As violator_name, " + + " c3.agency_mobile As violator_phone, " + + " c3.orderid, " + + " 'Hoarding' AS penaltyType " + + "FROM gcc_penalty_hoardings.bank_transactions bt " + + "LEFT JOIN gcc_penalty_hoardings.hoardings_info c3 " + + " ON bt.txnId = c3.orderid " + + "WHERE bt.txnDate BETWEEN ? AND ? " + + "AND c3.cby = ? " + + "ORDER BY bt.txnDate DESC"; + //System.out.println("SQL : " + sqlQuery); + //List> result = jdbcPenaltyTemplate.queryForList(sqlQuery); + return jdbcPenaltyTemplate.queryForList(sqlQuery, fromDate, toDate, loginId); + } + +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/privateToilets/controller/APIController.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/privateToilets/controller/APIController.java new file mode 100644 index 0000000..58e994d --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/privateToilets/controller/APIController.java @@ -0,0 +1,189 @@ +package in.gov.chennaicorporation.mobileservice.privateToilets.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.MultiValueMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import in.gov.chennaicorporation.mobileservice.privateToilets.service.ToiletService; + +@RequestMapping("/gccofficialapp/api/privatetoilets/") +@RestController("gccofficialappsprivatetoiltes") +public class APIController { + @Autowired + private ToiletService toiletService; + + @GetMapping(value="/getToiletsList") + public List getToiletsList(@RequestParam(value="loginId", required = true) String cby){ + return toiletService.getToiletsList(cby); + } + + @GetMapping("/toiletlistRest") + public List toiletlistRest(@RequestParam MultiValueMap formData, + @RequestParam(value = "latitude", required = true) String latitude, + @RequestParam(value = "longitude", required = true) String longitude) { + return toiletService.toiletlistRest(formData, latitude, longitude); + } + + @GetMapping("/toiletlistbylatlong") + public List toiletlistbylatlong(@RequestParam MultiValueMap formData, + @RequestParam(value = "latitude", required = true) String latitude, + @RequestParam(value = "longitude", required = true) String longitude, + //@RequestParam(value = "assetid", required = true) String id, + @RequestParam(value = "loginId", required = false) String loginId) { + return toiletService.toiletlistbylatlong(formData, latitude, longitude,loginId); + } + + @GetMapping(value="/getParentQuestionsList") + public List getParentQuestionsList(@RequestParam(value="loginId", required = false) String cby){ + return toiletService.getParentQuestionsList(); + } + + @GetMapping(value="/getChildQuestionsList") + public List getChildQuestionsList( + @RequestParam(value="loginId", required = false) String cby, + @RequestParam(value="pid", required = true) String pid + ){ + return toiletService.getChildQuestionsList(pid); + } + + @PostMapping(value="/saveFeedback") + public List saveFeedback( + @RequestParam(value="toilet_id", required = true) String toilet_id, + @RequestParam(value="loginId", required = true) String cby, + @RequestParam(value="latitude", required = true) String latitude, + @RequestParam(value="longitude", required = true) String longitude, + @RequestParam(value="zone", required = true) String zone, + @RequestParam(value="ward", required = true) String ward, + @RequestParam(value = "file", required = true) MultipartFile filedata, + @RequestParam(value="remarks", required = false) String remarks, + + @RequestParam(value="q1", required = false) String q1, + @RequestParam(value="q2", required = false) String q2, + @RequestParam(value="q3", required = false) String q3, + @RequestParam(value="q4", required = false) String q4, + @RequestParam(value="q5", required = false) String q5, + @RequestParam(value="q6", required = false) String q6, + @RequestParam(value="q7", required = false) String q7, + @RequestParam(value="q8", required = false) String q8, + @RequestParam(value="q9", required = false) String q9, + @RequestParam(value="q10", required = false) String q10, + @RequestParam(value="q11", required = false) String q11, + @RequestParam(value="q12", required = false) String q12, + @RequestParam(value="q13", required = false) String q13, + @RequestParam(value="q14", required = false) String q14, + @RequestParam(value="q15", required = false) String q15, + @RequestParam(value="q16", required = false) String q16, + @RequestParam(value="q17", required = false) String q17, + @RequestParam(value="q18", required = false) String q18, + @RequestParam(value="q19", required = false) String q19, + @RequestParam(value="q20", required = false) String q20, + @RequestParam(value="q21", required = false) String q21, + @RequestParam(value="q22", required = false) String q22, + @RequestParam(value="q23", required = false) String q23, + @RequestParam(value="q24", required = false) String q24, + @RequestParam(value="q25", required = false) String q25, + @RequestParam(value="q26", required = false) String q26, + @RequestParam(value="q27", required = false) String q27, + + @RequestParam(value="q1_image", required = false) MultipartFile q1_image, + @RequestParam(value="q2_image", required = false) MultipartFile q2_image, + @RequestParam(value="q3_image", required = false) MultipartFile q3_image, + @RequestParam(value="q4_image", required = false) MultipartFile q4_image, + @RequestParam(value="q5_image", required = false) MultipartFile q5_image, + @RequestParam(value="q6_image", required = false) MultipartFile q6_image, + @RequestParam(value="q7_image", required = false) MultipartFile q7_image, + @RequestParam(value="q8_image", required = false) MultipartFile q8_image, + @RequestParam(value="q9_image", required = false) MultipartFile q9_image, + @RequestParam(value="q10_image", required = false) MultipartFile q10_image, + @RequestParam(value="q11_image", required = false) MultipartFile q11_image, + @RequestParam(value="q12_image", required = false) MultipartFile q12_image, + @RequestParam(value="q13_image", required = false) MultipartFile q13_image, + @RequestParam(value="q14_image", required = false) MultipartFile q14_image, + @RequestParam(value="q15_image", required = false) MultipartFile q15_image, + @RequestParam(value="q16_image", required = false) MultipartFile q16_image, + @RequestParam(value="q17_image", required = false) MultipartFile q17_image, + @RequestParam(value="q18_image", required = false) MultipartFile q18_image, + @RequestParam(value="q19_image", required = false) MultipartFile q19_image, + @RequestParam(value="q20_image", required = false) MultipartFile q20_image, + @RequestParam(value="q21_image", required = false) MultipartFile q21_image, + @RequestParam(value="q22_image", required = false) MultipartFile q22_image, + @RequestParam(value="q23_image", required = false) MultipartFile q23_image, + @RequestParam(value="q24_image", required = false) MultipartFile q24_image, + @RequestParam(value="q25_image", required = false) MultipartFile q25_image, + @RequestParam(value="q26_image", required = false) MultipartFile q26_image, + @RequestParam(value="q27_image", required = false) MultipartFile q27_image + ) { + return toiletService.saveFeedback( + toilet_id, cby, latitude, longitude, zone, ward, + q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, + q11, q12, q13, q14, q15, q16, q17, q18, q19, q20, + q21, q22, q23, q24, q25, q26, q27, remarks, filedata, + q1_image, q2_image, q3_image, q4_image, q5_image, q6_image, q7_image, q8_image, q9_image, q10_image, + q11_image, q12_image, q13_image, q14_image, q15_image, q16_image, q17_image, q18_image, q19_image, q20_image, + q21_image, q22_image, q23_image, q24_image, q25_image, q26_image, q27_image + ); + } + + @GetMapping(value="/zoneReport") + public List zoneReport( + @RequestParam MultiValueMap formData, + @RequestParam(value="fromDate", required = true) String fromDate, + @RequestParam(value="toDate", required = true) String toDate, + @RequestParam(value="loginId", required = false) String cby + ){ + return toiletService.zoneReport(formData,fromDate,toDate,cby); + } + + @GetMapping(value="/wardReport") + public List wardReport( + @RequestParam MultiValueMap formData, + @RequestParam(value="fromDate", required = true) String fromDate, + @RequestParam(value="toDate", required = true) String toDate, + @RequestParam(value="zone", required = true) String zone, + @RequestParam(value="loginId", required = false) String cby + ){ + return toiletService.wardReport(formData,fromDate,toDate,zone,cby); + } + + @GetMapping(value="/toiletReport") + public List toiletReport( + @RequestParam MultiValueMap formData, + @RequestParam(value="fromDate", required = true) String fromDate, + @RequestParam(value="toDate", required = true) String toDate, + @RequestParam(value="ward", required = true) String ward, + @RequestParam(value="loginId", required = false) String cby + ){ + return toiletService.toiletReport(formData,fromDate,toDate,ward,cby); + } + + @GetMapping(value="/toiletDailyFeedbackReport") + public List toiletDailyFeedbackReport( + @RequestParam MultiValueMap formData, + @RequestParam(value="fromDate", required = true) String fromDate, + @RequestParam(value="toDate", required = true) String toDate, + @RequestParam(value="toilet_id", required = false) String toilet_id, + @RequestParam(value="type", required = true) String type, + @RequestParam(value="loginId", required = false) String cby + ){ + return toiletService.getToiletDailyFeedbackReport(formData,fromDate,toDate,toilet_id,type,cby); + } + + @GetMapping(value="/feedbackReport") + public List feedbackReport( + @RequestParam MultiValueMap formData, + @RequestParam(value="filterDate", required = true) String filterDate, + //@RequestParam(value="toDate", required = true) String toDate, + //@RequestParam(value="type", required = true) String type, + @RequestParam(value="toilet_id", required = true) String id, + @RequestParam(value="loginId", required = false) String cby + ){ + return toiletService.feedbackReport(formData,filterDate,id,cby); + } +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/privateToilets/controller/package-info.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/privateToilets/controller/package-info.java new file mode 100644 index 0000000..facb24e --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/privateToilets/controller/package-info.java @@ -0,0 +1 @@ +package in.gov.chennaicorporation.mobileservice.privateToilets.controller; \ No newline at end of file diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/privateToilets/package-info.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/privateToilets/package-info.java new file mode 100644 index 0000000..f9e50be --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/privateToilets/package-info.java @@ -0,0 +1 @@ +package in.gov.chennaicorporation.mobileservice.privateToilets; \ No newline at end of file diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/privateToilets/service/ToiletService.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/privateToilets/service/ToiletService.java new file mode 100644 index 0000000..e9c56c4 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/privateToilets/service/ToiletService.java @@ -0,0 +1,851 @@ +package in.gov.chennaicorporation.mobileservice.privateToilets.service; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.SecureRandom; +import java.sql.PreparedStatement; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Random; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.imageio.ImageIO; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.stream.ImageOutputStream; +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.core.env.Environment; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.MultiValueMap; +import org.springframework.web.multipart.MultipartFile; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import in.gov.chennaicorporation.mobileservice.gccactivity.service.DateTimeUtil; + +@Service +public class ToiletService { + + private JdbcTemplate jdbcToiletsTemplate; + private final Environment environment; + private String fileBaseUrl; + + private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + private static final int STRING_LENGTH = 15; + private static final Random RANDOM = new SecureRandom(); + + @Autowired + public void setDataSource(@Qualifier("mysqlPrivateToiletsDataSource") DataSource toiletsDataSource) { + this.jdbcToiletsTemplate = new JdbcTemplate(toiletsDataSource); + } + + @Autowired + public ToiletService(Environment environment) { + this.environment = environment; + this.fileBaseUrl=environment.getProperty("fileBaseUrl"); + } + + public static String generateRandomString() { + StringBuilder result = new StringBuilder(STRING_LENGTH); + for (int i = 0; i < STRING_LENGTH; i++) { + result.append(CHARACTERS.charAt(RANDOM.nextInt(CHARACTERS.length()))); + } + return result.toString(); + } + + public static String generateRandomFileString(int lenthval) { + StringBuilder result = new StringBuilder(lenthval); + for (int i = 0; i < lenthval; i++) { + result.append(CHARACTERS.charAt(RANDOM.nextInt(CHARACTERS.length()))); + } + return result.toString(); + } + + private byte[] compressImage(BufferedImage image, float quality) throws IOException { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(byteArrayOutputStream); + + ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next(); + writer.setOutput(imageOutputStream); + + ImageWriteParam param = writer.getDefaultWriteParam(); + if (param.canWriteCompressed()) { + param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); + param.setCompressionQuality(quality); + } + + writer.write(null, new javax.imageio.IIOImage(image, null, null), param); + + writer.dispose(); + imageOutputStream.close(); + + return byteArrayOutputStream.toByteArray(); + } + + public String fileUpload(String name, String id, MultipartFile file) { + + int lastInsertId = 0; + // Set the file path where you want to save it + String uploadDirectory = environment.getProperty("file.upload.directory"); + String serviceFolderName = environment.getProperty("private_toilets_foldername"); + var year = DateTimeUtil.getCurrentYear(); + var month = DateTimeUtil.getCurrentMonth(); + var date = DateTimeUtil.getCurrentDay(); + + uploadDirectory = uploadDirectory + serviceFolderName + year + "/" + month + "/" + date; + + try { + // Create directory if it doesn't exist + Path directoryPath = Paths.get(uploadDirectory); + if (!Files.exists(directoryPath)) { + Files.createDirectories(directoryPath); + } + + // Datetime string + String datetimetxt = DateTimeUtil.getCurrentDateTime(); + + datetimetxt = datetimetxt + "_"+ generateRandomFileString(6); // Attached Random text + + // File name + String fileName = name + "_" + id + "_" + datetimetxt + "_" + file.getOriginalFilename(); + fileName = fileName.replaceAll("\\s+", ""); // Remove space on filename + + String filePath = uploadDirectory + "/" + fileName; + + String filepath_txt = "/" + serviceFolderName + year + "/" + month + "/" + date + "/" + fileName; + + // Create a new Path object + Path path = Paths.get(filePath); + + // Get the bytes of the file + byte[] bytes = file.getBytes(); + + // Compress the image + BufferedImage image = ImageIO.read(new ByteArrayInputStream(bytes)); + byte[] compressedBytes = compressImage(image, 0.5f); // Compress with 50% quality + + // Write the bytes to the file + Files.write(path, compressedBytes); + + System.out.println(filePath); + return filepath_txt; + + } catch (IOException e) { + e.printStackTrace(); + return "Failed to save file " + file.getOriginalFilename(); + } + } + + public List> getToiletsList(String loginid) { + String sql = "SELECT *" + //+ ",CONCAT('"+fileBaseUrl+"/gccofficialapp/files',image) AS photo " + + " FROM `gcc_toilet_list` WHERE `isactive`=1"; + List> result = jdbcToiletsTemplate.queryForList(sql,loginid); + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "Toilets List."); + response.put("data", result); + + return Collections.singletonList(response); + } + + @Transactional + public List> toiletlistRest( + MultiValueMap formData, + String latitude, + String longitude) { + + String sqlWhere = ""; + + Map response = new HashMap<>(); + + if (latitude != null && longitude != null && !latitude.isBlank() && !latitude.isEmpty() && !longitude.isBlank() + && !longitude.isEmpty()) { + String sqlQuery = "SELECT gl.*, tf.last_feedback_date " + + "FROM gcc_toilet_list gl " + + "LEFT JOIN ( " + + " SELECT toilet_id, DATE_FORMAT(MAX(cdate), '%d-%m-%Y') AS last_feedback_date " + + " FROM toilet_feedback WHERE isactive = 1 " + + " GROUP BY toilet_id " + + ") tf ON tf.toilet_id = gl.id " + + "WHERE gl.isactive = 1 " + + " AND ( " + + " (6371008.8 * ACOS(ROUND( " + + " COS(RADIANS(" + latitude + ")) * COS(RADIANS(gl.latitude)) * " + + " COS(RADIANS(gl.longitude) - RADIANS(" + longitude + ")) + " + + " SIN(RADIANS(" + latitude + ")) * SIN(RADIANS(gl.latitude)), " + + " 9))) < 200 " + + " ) " + + "ORDER BY gl.id DESC"; + + List> result = jdbcToiletsTemplate.queryForList(sqlQuery); + + response.put("status", 200); + response.put("message", "Nearby toilet list."); + if(result.isEmpty()) { + response.put("message", "No toilet found nearby."); + } + response.put("data", result); + } + else { + response.put("status", 200); + response.put("message", "No toilet found nearby."); + } + return Collections.singletonList(response); + } + + @Transactional + public List> toiletlistbylatlong( + MultiValueMap formData, + String latitude, + String longitude, + //String id, + String loginid) { + + String sqlWhere = ""; + + Map response = new HashMap<>(); + + if (latitude != null && longitude != null && !latitude.isBlank() && !latitude.isEmpty() && !longitude.isBlank() + && !longitude.isEmpty()) { + /* + sqlWhere += " AND ((6371008.8 * acos(ROUND(cos(radians(" + latitude + + ")) * cos(radians(latitude)) * cos(radians(longitude) - radians(" + longitude + + ")) + sin(radians(" + latitude + ")) * sin(radians(latitude)), 9))) < 200)" + + " ORDER BY `id` DESC"; + */ + /* + String sqlQuery = "SELECT * " + //+ ", CONCAT('https://gccservices.in/gccofficialapp/files', image) AS photo\n" + + "FROM gcc_toilet_list " + + "WHERE isactive = 1 " + + " AND ( " + + " (6371008.8 * ACOS(ROUND( " + + " COS(RADIANS("+ latitude +")) * COS(RADIANS(latitude)) * " + + " COS(RADIANS(longitude) - RADIANS("+longitude+")) + " + + " SIN(RADIANS("+latitude+")) * SIN(RADIANS(latitude)), " + + " 9))) < 200 " + + " ) " + + "ORDER BY id DESC"; + */ + String sqlQuery = "SELECT gl.*, tf.last_feedback_date " + + "FROM gcc_toilet_list gl " + + "LEFT JOIN ( " + + " SELECT toilet_id, DATE_FORMAT(MAX(cdate), '%d-%m-%Y') AS last_feedback_date " + + " FROM toilet_feedback WHERE isactive = 1 " + + " GROUP BY toilet_id " + + ") tf ON tf.toilet_id = gl.id " + + "WHERE gl.isactive = 1 " + + " AND ( " + + " (6371008.8 * ACOS(ROUND( " + + " COS(RADIANS(" + latitude + ")) * COS(RADIANS(gl.latitude)) * " + + " COS(RADIANS(gl.longitude) - RADIANS(" + longitude + ")) + " + + " SIN(RADIANS(" + latitude + ")) * SIN(RADIANS(gl.latitude)), " + + " 9))) < 200 " + + " ) " + + "ORDER BY gl.id DESC"; + + List> result = jdbcToiletsTemplate.queryForList(sqlQuery); + + response.put("status", 200); + response.put("message", "Nearby toilet list."); + if(result.isEmpty()) { + response.put("message", "No toilet found nearby."); + } + response.put("data", result); + } + else { + response.put("status", 200); + response.put("message", "No toilet found nearby."); + } + return Collections.singletonList(response); + } + + public List> getParentQuestionsList() { + String sql = "SELECT " + + " ql.*, " + + " CASE " + + " WHEN (ql.question_type = 'select' OR ql.question_type = 'radio') THEN JSON_ARRAYAGG( " + + " JSON_OBJECT( " + + " 'option_id', qov.id, " + + " 'english_name', qov.name, " + + " 'value', qov.id, " + + " 'orderby', qov.orderby " + + " ) " + + " ) " + + " ELSE NULL " + + " END AS options " + + "FROM question_list ql " + + "LEFT JOIN question_option_values qov " + + " ON qov.qid = ql.id " + + " AND qov.isactive = 1 " + + " AND qov.isdelete = 0 " + + "WHERE ql.isactive = 1 " + + " AND ql.pid = 0 " + + "GROUP BY ql.id"; + + List> result = jdbcToiletsTemplate.queryForList(sql); + Iterator> iterator = result.iterator(); + ObjectMapper mapper = new ObjectMapper(); + while (iterator.hasNext()) { + Map row = iterator.next(); + Object optionsRaw = row.get("options"); + if (optionsRaw != null && optionsRaw instanceof String) { + try { + List> optionsParsed = mapper.readValue((String) optionsRaw, List.class); + + // Sort options by 'orderby' + optionsParsed.sort(Comparator.comparing(opt -> { + Object order = opt.get("orderby"); + return (order instanceof Number) ? ((Number) order).intValue() : 0; + })); + + row.put("options", optionsParsed); + } catch (Exception e) { + row.put("options", null); // fallback if malformed + } + } + } + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "Toilet Parent Question List."); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> getChildQuestionsList(String pid) { + String sql = "SELECT * FROM question_list WHERE isactive=1 AND `pid`=?"; + List> result = jdbcToiletsTemplate.queryForList(sql,pid); + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "Toilet Child Question List."); + response.put("data", result); + + return Collections.singletonList(response); + } + + @Transactional + public List> saveFeedback( + String toilet_id, + String cby, + String latitude, + String longitude, + String zone, + String ward, + String q1, String q2, String q3, String q4, String q5, String q6, String q7, String q8, String q9, String q10, + String q11, String q12, String q13, String q14, String q15, String q16, String q17, String q18, String q19, String q20, + String q21, String q22, String q23, String q24, String q25, String q26, String q27, + String remarks, MultipartFile filedata, + MultipartFile q1_image, MultipartFile q2_image, MultipartFile q3_image, MultipartFile q4_image, MultipartFile q5_image, + MultipartFile q6_image, MultipartFile q7_image, MultipartFile q8_image, MultipartFile q9_image, MultipartFile q10_image, + MultipartFile q11_image, MultipartFile q12_image, MultipartFile q13_image, MultipartFile q14_image, MultipartFile q15_image, + MultipartFile q16_image, MultipartFile q17_image, MultipartFile q18_image, MultipartFile q19_image, MultipartFile q20_image, + MultipartFile q21_image, MultipartFile q22_image, MultipartFile q23_image, MultipartFile q24_image, MultipartFile q25_image, + MultipartFile q26_image, MultipartFile q27_image + ) { + Map response = new HashMap<>(); + List> result = new ArrayList<>(); + + String feedbackimg = fileUpload("feedback", "main", filedata); + + String type = ""; + + // Prepare question image uploads + MultipartFile[] files = { + q1_image, q2_image, q3_image, q4_image, q5_image, q6_image, q7_image, q8_image, q9_image, q10_image, + q11_image, q12_image, q13_image, q14_image, q15_image, q16_image, q17_image, q18_image, q19_image, q20_image, + q21_image, q22_image, q23_image, q24_image, q25_image, q26_image, q27_image + }; + String[] imagePaths = new String[27]; + for (int i = 0; i < files.length; i++) { + if (files[i] != null && !files[i].isEmpty()) { + imagePaths[i] = fileUpload(String.valueOf(i + 1), "q" + (i + 1), files[i]); + } else { + imagePaths[i] = ""; + } + } + + // Insert query + String insertSql = "INSERT INTO toilet_feedback (toilet_id, cby, latitude, longitude, zone, ward, image, remarks, type, " + + "q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12, q13, q14, q15, q16, q17, q18, q19, q20, q21, q22, q23, q24, q25, q26, q27, " + + "q1_image, q2_image, q3_image, q4_image, q5_image, q6_image, q7_image, q8_image, q9_image, q10_image, q11_image, q12_image, " + + "q13_image, q14_image, q15_image, q16_image, q17_image, q18_image, q19_image, q20_image, q21_image, q22_image, q23_image, " + + "q24_image, q25_image, q26_image, q27_image) " + + "VALUES (" + "?,".repeat(9 + 27 + 27).replaceAll(",$", "") + ")"; + + KeyHolder keyHolder = new GeneratedKeyHolder(); + + int affectedRows = jdbcToiletsTemplate.update(connection -> { + PreparedStatement ps = connection.prepareStatement(insertSql, new String[]{"id"}); + int i = 1; + ps.setString(i++, toilet_id); + ps.setString(i++, cby); + ps.setString(i++, latitude); + ps.setString(i++, longitude); + ps.setString(i++, zone); + ps.setString(i++, ward); + ps.setString(i++, feedbackimg); + ps.setString(i++, remarks); + ps.setString(i++, type); + + // 27 question answers + for (String q : new String[]{q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, + q11, q12, q13, q14, q15, q16, q17, q18, q19, q20, + q21, q22, q23, q24, q25, q26, q27}) { + ps.setString(i++, q); + } + + // 27 question image paths + for (String path : imagePaths) { + ps.setString(i++, path); + } + + return ps; + }, keyHolder); + + if (affectedRows > 0) { + int lastInsertId = keyHolder.getKey().intValue(); + response.put("insertId", lastInsertId); + response.put("status", "success"); + response.put("message", "Feedback inserted successfully."); + } else { + response.put("status", "error"); + response.put("message", "Insert failed."); + } + + result.add(response); + return result; + } + + // Report + + @Transactional + public List> zoneReport( + MultiValueMap formData, + String fromDate, + String toDate, + String loginid) { + + String sqlQuery = "SELECT " + + " `gcc_toilet_list`.`zone`, " + + " COUNT(DISTINCT `gcc_toilet_list`.`id`) AS Total_Toilets, " + + " COUNT(DISTINCT `toilet_feedback`.`toilet_id`) AS Completed, " + + " (COUNT(DISTINCT gcc_toilet_list.id) - COUNT(DISTINCT toilet_feedback.toilet_id)) AS Pending " + + "FROM " + + " `gcc_toilet_list` " + + "LEFT JOIN " + + " `toilet_feedback` " + + " ON `toilet_feedback`.`toilet_id` = `gcc_toilet_list`.`id` " + + " AND `toilet_feedback`.`isactive` = 1 " + + " AND DATE(`toilet_feedback`.`cdate`) BETWEEN STR_TO_DATE(?, '%d-%m-%Y') AND STR_TO_DATE(?, '%d-%m-%Y') " + + "WHERE " + //+ " `gcc_toilet_list`.`user_id` = ? AND " + + " `gcc_toilet_list`.`isactive` = 1 " + + "GROUP BY " + + " `gcc_toilet_list`.`zone` " + + "ORDER BY " + + " `gcc_toilet_list`.`zone`"; + + List> result = jdbcToiletsTemplate.queryForList(sqlQuery, fromDate, toDate); + Map response = new HashMap<>(); + response.put("status", 200); + response.put("message", "Zone report."); + if(result.isEmpty()) { + response.put("message", "No data found."); + } + response.put("data", result); + + return Collections.singletonList(response); + } + + @Transactional + public List> wardReport( + MultiValueMap formData, + String fromDate, + String toDate, + String zone, + String loginid) { + + String sqlQuery = "SELECT " + + " `gcc_toilet_list`.`ward`, " + + " COUNT(DISTINCT `gcc_toilet_list`.`id`) AS Total_Toilets, " + + " COUNT(DISTINCT `toilet_feedback`.`toilet_id`) AS Completed, " + + " (COUNT(DISTINCT gcc_toilet_list.id) - COUNT(DISTINCT toilet_feedback.toilet_id)) AS Pending " + + "FROM " + + " `gcc_toilet_list` " + + "LEFT JOIN " + + " `toilet_feedback` " + + " ON `toilet_feedback`.`toilet_id` = `gcc_toilet_list`.`id` " + + " AND `toilet_feedback`.`isactive` = 1 " + + " AND DATE(`toilet_feedback`.`cdate`) BETWEEN STR_TO_DATE(?, '%d-%m-%Y') AND STR_TO_DATE(?, '%d-%m-%Y') " + + "WHERE " + + " `gcc_toilet_list`.`zone` = ? AND " + + " `gcc_toilet_list`.`isactive` = 1 " + + "GROUP BY " + + " `gcc_toilet_list`.`ward` " + + "ORDER BY " + + " `gcc_toilet_list`.`ward`"; + + List> result = jdbcToiletsTemplate.queryForList(sqlQuery, fromDate, toDate, zone); + Map response = new HashMap<>(); + response.put("status", 200); + response.put("message", "Ward report."); + if(result.isEmpty()) { + response.put("message", "No data found."); + } + response.put("data", result); + + return Collections.singletonList(response); + } + + public static List getDateRange(String start, String end) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); + LocalDate startDate = LocalDate.parse(start, formatter); + LocalDate endDate = LocalDate.parse(end, formatter); + List dates = new ArrayList<>(); + + while (!startDate.isAfter(endDate)) { + dates.add(startDate.format(formatter)); + startDate = startDate.plusDays(1); + } + + return dates; + } + + @Transactional + public List> toiletReport( + MultiValueMap formData, + String fromDate, + String toDate, + String ward, + String loginid) { + + String sqlQuery = "SELECT " + + " gtl.id AS toilet_id, " + + " gtl.pct_name AS name, " + + " gtl.zone, " + + " gtl.ward, " + + " " + + " DATEDIFF( " + + " STR_TO_DATE(?, '%d-%m-%Y'), " + + " STR_TO_DATE(?, '%d-%m-%Y') " + + " ) + 1 AS total_inspection_need_to_be_done, " + + " " + + " COUNT(DISTINCT DATE(tf.cdate)) AS total_inspection_done, " + + " " + + " ( " + + " DATEDIFF( " + + " STR_TO_DATE(?, '%d-%m-%Y'), " + + " STR_TO_DATE(?, '%d-%m-%Y') " + + " ) + 1 " + + " - COUNT(DISTINCT DATE(tf.cdate)) " + + " ) AS total_inspection_pending " + + " " + + "FROM " + + " gcc_toilet_list gtl " + + "LEFT JOIN " + + " toilet_feedback tf ON tf.toilet_id = gtl.id " + + " AND tf.isactive = 1 " + + " AND DATE(tf.cdate) BETWEEN STR_TO_DATE(?, '%d-%m-%Y') AND STR_TO_DATE(?, '%d-%m-%Y') " + + " " + + "WHERE " + + " gtl.isactive = 1 " + + " AND gtl.ward = ? " + + " " + + "GROUP BY " + + " gtl.id " + + "ORDER BY " + + " gtl.id"; + + List> result = jdbcToiletsTemplate.queryForList( + sqlQuery, + toDate, fromDate, + toDate, fromDate, + fromDate, toDate, + ward + ); + Map response = new HashMap<>(); + response.put("status", 200); + response.put("message", "Toilet list report."); + if(result.isEmpty()) { + response.put("message", "No data found."); + } + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> getToiletDailyFeedbackReport(MultiValueMap formData, + String fromDate, + String toDate, + String toilet_id, + String type, + String loginid) { + List> finalResult = new ArrayList<>(); + + // Step 1: Get all dates between fromDate and toDate + List allDates = getDateRange(fromDate, toDate); + + // Step 2: Execute the SQL + String sql = "SELECT gtl.id AS toilet_id, gtl.pct_name, gtl.zone, gtl.ward, " + + "gtl.latitude, gtl.longitude, " + + "MAX(tf.image) AS image, " + + "GROUP_CONCAT(DATE(tf.cdate) ORDER BY tf.cdate ASC) AS feedback_dates " + + "FROM gcc_toilet_list gtl " + + "LEFT JOIN toilet_feedback tf ON tf.toilet_id = gtl.id AND tf.isactive = 1 " + + "AND DATE(tf.cdate) BETWEEN STR_TO_DATE(?, '%d-%m-%Y') AND STR_TO_DATE(?, '%d-%m-%Y') " + + "WHERE gtl.id = ? AND gtl.isactive = 1 " + + "GROUP BY gtl.id"; + + List> toiletData = jdbcToiletsTemplate.queryForList(sql, fromDate, toDate, toilet_id); + + for (Map toilet : toiletData) { + Map report = new LinkedHashMap<>(); + String toiletId = toilet.get("toilet_id").toString(); + String image = toilet.get("image") != null ? toilet.get("image").toString() : ""; + String feedbackImage = image.isEmpty() ? "" : fileBaseUrl+"/gccofficialapp/files" + image; + + report.put("id", toiletId); + report.put("name", toilet.get("pct_name")); + report.put("zone", toilet.get("zone")); + report.put("ward", toilet.get("ward")); + report.put("latitude", toilet.get("latitude")); + report.put("longitude", toilet.get("longitude")); + report.put("photo", feedbackImage); + + // Step 3: Build Completed Dates + List> completedDates = new ArrayList<>(); + List> pendingDates = new ArrayList<>(); + + // if(toilet.get("toilet_id").equals("59")) { + System.out.println("Toilet"+toilet.get("toilet_id")+" :" + toilet.get("feedback_dates")); + //} + + String[] completed = Optional.ofNullable(toilet.get("feedback_dates")) + .map(Object::toString) + .map(d -> d.split(",")) + .orElse(new String[0]); + + // Set completedSet = new HashSet<>(Arrays.asList(completed)); + + DateTimeFormatter fromFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + DateTimeFormatter toFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); + + String[] completedRaw = Optional.ofNullable(toilet.get("feedback_dates")) + .map(Object::toString) + .map(d -> d.split(",")) + .orElse(new String[0]); + + Set completedSet = Arrays.stream(completedRaw) + .map(date -> { + try { + return LocalDate.parse(date.trim(), fromFormatter).format(toFormatter); + } catch (Exception e) { + return ""; // skip malformed + } + }) + .filter(s -> !s.isEmpty()) + .collect(Collectors.toSet()); + + for (String date : allDates) { + Map statusMap = new HashMap<>(); + statusMap.put("Date", date); + if (completedSet.contains(date)) { + statusMap.put("Status", "Done"); + completedDates.add(statusMap); + } else { + statusMap.put("Status", "NotDone"); + pendingDates.add(statusMap); + } + } + + if("completed".equals(type)) { + report.put("Dates", completedDates); + } + else { + report.put("Dates", pendingDates); + } + + + finalResult.add(report); + } + + return finalResult; + } + + @Transactional + public List> toiletReport2( + MultiValueMap formData, + String fromDate, + String toDate, + String ward, + String loginid) { + + String sqlQuery = "SELECT " + + " `gcc_toilet_list`.`id`,`gcc_toilet_list`.`name`,`gcc_toilet_list`.`zone`,`gcc_toilet_list`.`ward`, " + + " CONCAT('"+fileBaseUrl+"/gccofficialapp/files', `toilet_feedback`.`image`) AS photo," + + " COUNT(`toilet_feedback`.`toilet_id`) AS Completed " + + "FROM " + + " `gcc_toilet_list` " + + "LEFT JOIN " + + " `toilet_feedback` " + + " ON `toilet_feedback`.`toilet_id` = `gcc_toilet_list`.`id` " + + " AND `toilet_feedback`.`isactive` = 1 " + + " AND DATE(`toilet_feedback`.`cdate`) BETWEEN STR_TO_DATE(?, '%d-%m-%Y') AND STR_TO_DATE(?, '%d-%m-%Y') " + + "WHERE " + + " `gcc_toilet_list`.`ward` = ? AND " + + " `gcc_toilet_list`.`isactive` = 1 " + + "GROUP BY " + + " `gcc_toilet_list`.`id` " + + "ORDER BY " + + " `gcc_toilet_list`.`id`"; + + List> result = jdbcToiletsTemplate.queryForList(sqlQuery, fromDate, toDate, ward); + Map response = new HashMap<>(); + response.put("status", 200); + response.put("message", "Toilet list report."); + if(result.isEmpty()) { + response.put("message", "No data found."); + } + response.put("data", result); + + return Collections.singletonList(response); + } + + @Transactional + public List> feedbackReport( + MultiValueMap formData, + String filterDate, + String toiletid, + String loginid) { + + Map response = new HashMap<>(); + + String sqlQuery = "SELECT " + + " gtl.id AS assetid, " + + " gtl.pct_name AS name, " + + " gtl.zone, " + + " gtl.ward, " + + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files', tf.image) AS toiletPhoto, " + + " DATE_FORMAT(tf.cdate, '%d-%m-%Y %I:%i %p') AS feedbackDate, " + + " tf.*, " + + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files', tf.image) AS feedbackPhoto " + + "FROM gcc_toilet_list gtl " + + "RIGHT JOIN toilet_feedback tf ON tf.toilet_id = gtl.id AND tf.isactive = 1 " + + " AND DATE(tf.cdate) = STR_TO_DATE(?, '%d-%m-%Y') " + + "WHERE gtl.id = ? AND gtl.isactive = 1 " + + "ORDER BY feedbackDate LIMIT 1"; + + List> result = jdbcToiletsTemplate.queryForList(sqlQuery, filterDate, toiletid); + List> finalQA = new ArrayList<>(); + + if (!result.isEmpty()) { + Map feedback = result.get(0); + + // 1. Load all questions + String questionSql = "SELECT ql.*, " + + "CASE WHEN (ql.question_type IN ('select', 'radio')) THEN JSON_ARRAYAGG(JSON_OBJECT( " + + " 'option_id', qov.id, " + + " 'english_name', qov.name, " + + " 'value', qov.id, " + + " 'orderby', qov.orderby " + + ")) ELSE NULL END AS options " + + "FROM question_list ql " + + "LEFT JOIN question_option_values qov ON qov.qid = ql.id " + + "AND qov.isactive = 1 AND qov.isdelete = 0 " + + "WHERE (ql.isactive = 1 OR ql.showonreport = 1) " + + "GROUP BY ql.id"; + List> questions = jdbcToiletsTemplate.queryForList(questionSql); + + // 2. Build answer map from feedback row + Map answerMap = new HashMap<>(); + for (int i = 1; i <= 27; i++) { + String key = "q" + i; + Object val = feedback.get(key); + answerMap.put(String.valueOf(i), val != null ? val.toString() : ""); + } + + // 3. Combine Questions + Answers + Optional Images + for (Map q : questions) { + Map entry = new HashMap<>(); + String qid = q.get("id") != null ? q.get("id").toString() : ""; + + entry.put("qid", qid); + entry.put("question", q.get("q_english")); + entry.put("question_type", q.get("question_type")); + String answerValue = answerMap.getOrDefault(qid, ""); + + if (q.get("question_type") != null && + (q.get("question_type").toString().equalsIgnoreCase("select") || + q.get("question_type").toString().equalsIgnoreCase("radio"))) { + + // Resolve the label from options + if (q.get("options") != null && !answerValue.isBlank()) { + try { + List> options = new ObjectMapper().readValue(q.get("options").toString(), List.class); + for (Map opt : options) { + if (opt.get("option_id").toString().equals(answerValue)) { + answerValue = opt.get("english_name").toString(); + break; + } + } + } catch (Exception e) { + // fallback: leave answerValue as-is + } + } + } + + entry.put("answer", answerValue); + entry.put("img_required", q.get("img_required")); + + // Optional image + String imageField = "q" + qid + "_image"; + if (feedback.containsKey(imageField)) { + Object imgPath = feedback.get(imageField); + if (imgPath != null && !imgPath.toString().isBlank()) { + entry.put("image", fileBaseUrl + "/gccofficialapp/files" + imgPath.toString()); + } + } + + finalQA.add(entry); + } + + response.put("status", 200); + response.put("message", "Feedback list report."); + response.put("data", result); + response.put("question", finalQA); + } else { + response.put("status", 200); + response.put("message", "No data found."); + response.put("data", Collections.emptyList()); + response.put("question", Collections.emptyList()); + } + + return Collections.singletonList(response); + } +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/privateToilets/service/package-info.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/privateToilets/service/package-info.java new file mode 100644 index 0000000..358764e --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/privateToilets/service/package-info.java @@ -0,0 +1 @@ +package in.gov.chennaicorporation.mobileservice.privateToilets.service; \ No newline at end of file diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/roadcut/controller/RoadCutController.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/roadcut/controller/RoadCutController.java new file mode 100644 index 0000000..5b7a429 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/roadcut/controller/RoadCutController.java @@ -0,0 +1,130 @@ +package in.gov.chennaicorporation.mobileservice.roadcut.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import in.gov.chennaicorporation.mobileservice.roadcut.service.RoadCutService; + +@RequestMapping("/gccofficialapp/api/readcut/") +@RestController("restRoadCut") +public class RoadCutController { + @Autowired + private RoadCutService roadCutService; + + @GetMapping("/fetch-roadcut-json") + public ResponseEntity loadData( + @RequestParam("fromdate") String fromDate, + @RequestParam("todate") String toDate) { + try { + roadCutService.fetchAndSave(fromDate,toDate); + return ResponseEntity.ok("Data saved successfully"); + } catch (Exception e) { + return ResponseEntity.status(500).body("Error: " + e.getMessage()); + } + } + + // TNEB & Metro Water + @GetMapping(value="/get-roadcut-list") + public List getRoadCutList(@RequestParam(value="loginId", required = true) String cby){ + return roadCutService.getRoadCutList(cby); + } + + + @GetMapping(value="/check-roadcut-loation") + public List getLoactionCheck( + @RequestParam(value="loginId", required = true) String cby, + @RequestParam(value="refId", required = true) String refid, + @RequestParam(value="streetId", required = true) String streetid, + @RequestParam(value="streetName", required = true) String streetname + ){ + return roadCutService.getLoactionCheck(cby,refid,streetid,streetname); + } + + + @GetMapping(value="/get-roadcut-details") + public List getRoadCutDetails( + @RequestParam(value="loginId", required = true) String cby, + @RequestParam(value="refId", required = true) String refid + ){ + return roadCutService.getRoadCutDetails(cby,refid); + } + + @PostMapping(value="/saveAction") + public List saveFeedback( + @RequestParam("uid") String uid, + @RequestParam("cby") String cby, + @RequestParam("latitude") String latitude, + @RequestParam("longitude") String longitude, + @RequestParam("zone") String zone, + @RequestParam("ward") String ward, + @RequestParam("streetid") String streetid, + @RequestParam("streetname") String streetname, + @RequestParam("action") String action, + @RequestParam("workstatus") String workstatus, + @RequestParam("remarks") String remarks, + @RequestParam("nocid") String nocid, + @RequestParam(value = "file", required = false) MultipartFile filedata) { + + return roadCutService.saveStatusUpdate( + uid, cby, latitude, longitude, zone, ward, streetid, + streetname, action, workstatus, remarks, nocid, filedata + ); + + } + + // AE GCC Officer + @GetMapping(value="/get-roadcut-list-offical") + public List getRoadCutList_offical(@RequestParam(value="loginId", required = true) String cby){ + return roadCutService.getRoadCutList_offical(cby); + } + + @GetMapping(value="/check-roadcut-loation-offical") + public List getLoactionCheck_offical( + @RequestParam(value="loginId", required = true) String cby, + @RequestParam(value="refId", required = true) String refid, + @RequestParam(value="streetId", required = true) String streetid, + @RequestParam(value="streetName", required = true) String streetname + ){ + return roadCutService.getLoactionCheck(cby,refid,streetid,streetname); + } + + + @GetMapping(value="/get-roadcut-details-offical") + public List getRoadCutDetails_offical( + @RequestParam(value="loginId", required = true) String cby, + @RequestParam(value="refId", required = true) String refid + ){ + return roadCutService.getRoadCutDetails_offical(cby,refid); + } + + @PostMapping(value="/saveAction-offical") + public List saveFeedback_offical( + @RequestParam("uid") String uid, + @RequestParam("cby") String cby, + @RequestParam("latitude") String latitude, + @RequestParam("longitude") String longitude, + @RequestParam("zone") String zone, + @RequestParam("ward") String ward, + @RequestParam("streetid") String streetid, + @RequestParam("streetname") String streetname, + @RequestParam("action") String action, + @RequestParam("workstatus") String workstatus, + @RequestParam("remarks") String remarks, + @RequestParam("nocid") String nocid, + @RequestParam(value = "file", required = false) MultipartFile filedata) { + + return roadCutService.saveStatusUpdate_offical( + uid, cby, latitude, longitude, zone, ward, streetid, + streetname, action, workstatus, remarks, nocid, filedata + ); + + } +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/roadcut/controller/package-info.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/roadcut/controller/package-info.java new file mode 100644 index 0000000..b9e17f1 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/roadcut/controller/package-info.java @@ -0,0 +1 @@ +package in.gov.chennaicorporation.mobileservice.roadcut.controller; \ No newline at end of file diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/roadcut/modelclass/RoadCutDetail.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/roadcut/modelclass/RoadCutDetail.java new file mode 100644 index 0000000..fb65cdf --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/roadcut/modelclass/RoadCutDetail.java @@ -0,0 +1,33 @@ +package in.gov.chennaicorporation.mobileservice.roadcut.modelclass; + +public class RoadCutDetail { + public String NOC_APP_REM; + public String ROAD_BREADTH; + public String DAMAGE_FEE; + public String ROAD_REMARKS; + public String DEPT_NAME; + public String PAYMENT_STATUS; + public String STREET; + public String LOC; + public String TENT_WORK_STARTDATE; + public String ROAD_LENGTH; + public String NOC_STATUS; + public String APPLICATION_NO; + public String INTERLOCKING; + public String NOC_APP_FROMDT; + public String APPLICATION_DATE; + public String AREA; + public String ADDRESS; + public String WARD; + public String DEPOSIT_WORKS_CATEGORY; + public String ZONE; + public String UNIQUEID; + public String TENT_WORK_ENDDATE; + public String APP_STATUS; + public String NOC_APP_TODT; + public String NOC_APP_DATE; + public String NO_OF_PIT; + public String APPLICANT_NAME; + public String TYPE_OF_ROAD; + public String ROAD_DEPTH; +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/roadcut/modelclass/RoadCutResponse.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/roadcut/modelclass/RoadCutResponse.java new file mode 100644 index 0000000..f31ce97 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/roadcut/modelclass/RoadCutResponse.java @@ -0,0 +1,9 @@ +package in.gov.chennaicorporation.mobileservice.roadcut.modelclass; + +import java.util.List; + +public class RoadCutResponse { + public List ListResult; + public String Message; + public boolean ResultStatus; +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/roadcut/modelclass/package-info.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/roadcut/modelclass/package-info.java new file mode 100644 index 0000000..e708e48 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/roadcut/modelclass/package-info.java @@ -0,0 +1 @@ +package in.gov.chennaicorporation.mobileservice.roadcut.modelclass; \ No newline at end of file diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/roadcut/package-info.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/roadcut/package-info.java new file mode 100644 index 0000000..3855ae5 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/roadcut/package-info.java @@ -0,0 +1 @@ +package in.gov.chennaicorporation.mobileservice.roadcut; \ No newline at end of file diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/roadcut/service/RoadCutService.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/roadcut/service/RoadCutService.java new file mode 100644 index 0000000..8e15434 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/roadcut/service/RoadCutService.java @@ -0,0 +1,976 @@ +package in.gov.chennaicorporation.mobileservice.roadcut.service; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.SecureRandom; +import java.sql.PreparedStatement; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import javax.imageio.ImageIO; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.stream.ImageOutputStream; +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.core.env.Environment; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.multipart.MultipartFile; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import in.gov.chennaicorporation.mobileservice.gccactivity.service.DateTimeUtil; +import in.gov.chennaicorporation.mobileservice.roadcut.modelclass.RoadCutDetail; +import in.gov.chennaicorporation.mobileservice.roadcut.modelclass.RoadCutResponse; + +@Service +public class RoadCutService { + + @Autowired + private JdbcTemplate jdbcRoadCutTemplate; + private final Environment environment; + private String fileBaseUrl; + + private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + private static final int STRING_LENGTH = 15; + private static final Random RANDOM = new SecureRandom(); + + @Autowired + public void setDataSource(@Qualifier("mysqlRoadCutDataSource") DataSource roadCutDataSource) { + this.jdbcRoadCutTemplate = new JdbcTemplate(roadCutDataSource); + } + + @Autowired + public RoadCutService(Environment environment) { + this.environment = environment; + this.fileBaseUrl=environment.getProperty("fileBaseUrl"); + } + + public static String generateRandomString() { + StringBuilder result = new StringBuilder(STRING_LENGTH); + for (int i = 0; i < STRING_LENGTH; i++) { + result.append(CHARACTERS.charAt(RANDOM.nextInt(CHARACTERS.length()))); + } + return result.toString(); + } + + public static String generateRandomFileString(int lenthval) { + StringBuilder result = new StringBuilder(lenthval); + for (int i = 0; i < lenthval; i++) { + result.append(CHARACTERS.charAt(RANDOM.nextInt(CHARACTERS.length()))); + } + return result.toString(); + } + + private byte[] compressImage(BufferedImage image, float quality) throws IOException { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(byteArrayOutputStream); + + ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next(); + writer.setOutput(imageOutputStream); + + ImageWriteParam param = writer.getDefaultWriteParam(); + if (param.canWriteCompressed()) { + param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); + param.setCompressionQuality(quality); + } + + writer.write(null, new javax.imageio.IIOImage(image, null, null), param); + + writer.dispose(); + imageOutputStream.close(); + + return byteArrayOutputStream.toByteArray(); + } + + public String fileUpload(String name, String id, MultipartFile file) { + + int lastInsertId = 0; + // Set the file path where you want to save it + String uploadDirectory = environment.getProperty("file.upload.directory"); + String serviceFolderName = environment.getProperty("roadcut_foldername"); + var year = DateTimeUtil.getCurrentYear(); + var month = DateTimeUtil.getCurrentMonth(); + var date = DateTimeUtil.getCurrentDay(); + + uploadDirectory = uploadDirectory + serviceFolderName + year + "/" + month + "/" + date; + + try { + // Create directory if it doesn't exist + Path directoryPath = Paths.get(uploadDirectory); + if (!Files.exists(directoryPath)) { + Files.createDirectories(directoryPath); + } + + // Datetime string + String datetimetxt = DateTimeUtil.getCurrentDateTime(); + + datetimetxt = datetimetxt + "_"+ generateRandomFileString(6); // Attached Random text + + // File name + String fileName = name + "_" + id + "_" + datetimetxt + "_" + file.getOriginalFilename(); + fileName = fileName.replaceAll("\\s+", ""); // Remove space on filename + + String filePath = uploadDirectory + "/" + fileName; + + String filepath_txt = "/" + serviceFolderName + year + "/" + month + "/" + date + "/" + fileName; + + // Create a new Path object + Path path = Paths.get(filePath); + + // Get the bytes of the file + byte[] bytes = file.getBytes(); + + // Compress the image + BufferedImage image = ImageIO.read(new ByteArrayInputStream(bytes)); + byte[] compressedBytes = compressImage(image, 0.5f); // Compress with 50% quality + + // Write the bytes to the file + Files.write(path, compressedBytes); + + System.out.println(filePath); + return filepath_txt; + + } catch (IOException e) { + e.printStackTrace(); + return "Failed to save file " + file.getOriginalFilename(); + } + } + + private String safeValue(String val) { + return (val == null || val.trim().equalsIgnoreCase("N/A")) ? null : val.trim(); + } + + public void fetchAndSave(String fromDate, String toDate) throws Exception { + + // expected format = dd-MM-yyyy → convert to dd/MM/yyyy for URL + String formattedFromDate = fromDate.replace("-", "/"); + + String formattedToDate = toDate.replace("-", "/"); + + String url = "http://coc-staging.egovernments.org:9980/pgr/external/mobileservice?" + + "serviceId=common_api" + + "&jsonResp=Yes" + + "&subService=getRoadcutselfDet" + + "&fromDate=" + formattedFromDate + + "&toDate=" + formattedToDate; + + RestTemplate restTemplate = new RestTemplate(); + String json = restTemplate.getForObject(url, String.class); + + ObjectMapper mapper = new ObjectMapper(); + RoadCutResponse response = mapper.readValue(json, RoadCutResponse.class); + + String sql = "INSERT INTO road_cut_details (" + + "NOC_APP_REM, ROAD_BREADTH, DAMAGE_FEE, ROAD_REMARKS, DEPT_NAME, PAYMENT_STATUS, " + + "STREET, LOC, TENT_WORK_STARTDATE, ROAD_LENGTH, NOC_STATUS, APPLICATION_NO, " + + "INTERLOCKING, NOC_APP_FROMDT, APPLICATION_DATE, AREA, ADDRESS, WARD, " + + "DEPOSIT_WORKS_CATEGORY, ZONE, UNIQUEID, TENT_WORK_ENDDATE, APP_STATUS, " + + "NOC_APP_TODT, NOC_APP_DATE, NO_OF_PIT, APPLICANT_NAME, TYPE_OF_ROAD, ROAD_DEPTH) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"+ + "ON DUPLICATE KEY UPDATE " + + "NOC_APP_REM = VALUES(NOC_APP_REM), " + + "ROAD_BREADTH = VALUES(ROAD_BREADTH), " + + "DAMAGE_FEE = VALUES(DAMAGE_FEE), " + + "ROAD_REMARKS = VALUES(ROAD_REMARKS), " + + "DEPT_NAME = VALUES(DEPT_NAME), " + + "PAYMENT_STATUS = VALUES(PAYMENT_STATUS), " + + "STREET = VALUES(STREET), " + + "LOC = VALUES(LOC), " + + "TENT_WORK_STARTDATE = VALUES(TENT_WORK_STARTDATE), " + + "ROAD_LENGTH = VALUES(ROAD_LENGTH), " + + "NOC_STATUS = VALUES(NOC_STATUS), " + + "APPLICATION_NO = VALUES(APPLICATION_NO), " + + "INTERLOCKING = VALUES(INTERLOCKING), " + + "NOC_APP_FROMDT = VALUES(NOC_APP_FROMDT), " + + "APPLICATION_DATE = VALUES(APPLICATION_DATE), " + + "AREA = VALUES(AREA), " + + "ADDRESS = VALUES(ADDRESS), " + + "WARD = VALUES(WARD), " + + "DEPOSIT_WORKS_CATEGORY = VALUES(DEPOSIT_WORKS_CATEGORY), " + + "ZONE = VALUES(ZONE), " + + "TENT_WORK_ENDDATE = VALUES(TENT_WORK_ENDDATE), " + + "APP_STATUS = VALUES(APP_STATUS), " + + "NOC_APP_TODT = VALUES(NOC_APP_TODT), " + + "NOC_APP_DATE = VALUES(NOC_APP_DATE), " + + "NO_OF_PIT = VALUES(NO_OF_PIT), " + + "APPLICANT_NAME = VALUES(APPLICANT_NAME), " + + "TYPE_OF_ROAD = VALUES(TYPE_OF_ROAD), " + + "ROAD_DEPTH = VALUES(ROAD_DEPTH)"; + + for (RoadCutDetail rc : response.ListResult) { + //System.out.println("======="); + //System.out.println(mapper.writeValueAsString(rc)); + //System.out.println("======="); + try { + jdbcRoadCutTemplate.update(sql, + safeValue(rc.NOC_APP_REM), + safeValue(rc.ROAD_BREADTH), + safeValue(rc.DAMAGE_FEE), + safeValue(rc.ROAD_REMARKS), + safeValue(rc.DEPT_NAME), + safeValue(rc.PAYMENT_STATUS), + safeValue(rc.STREET), + safeValue(rc.LOC), + safeValue(rc.TENT_WORK_STARTDATE), + safeValue(rc.ROAD_LENGTH), + safeValue(rc.NOC_STATUS), + safeValue(rc.APPLICATION_NO), + safeValue(rc.INTERLOCKING), + safeValue(rc.NOC_APP_FROMDT), + safeValue(rc.APPLICATION_DATE), + safeValue(rc.AREA), + safeValue(rc.ADDRESS), + safeValue(rc.WARD), + safeValue(rc.DEPOSIT_WORKS_CATEGORY), + safeValue(rc.ZONE), + safeValue(rc.UNIQUEID), // NOTE: This is NOT NULL. Must not be null! + safeValue(rc.TENT_WORK_ENDDATE), + safeValue(rc.APP_STATUS), + safeValue(rc.NOC_APP_TODT), + safeValue(rc.NOC_APP_DATE), + safeValue(rc.NO_OF_PIT), + safeValue(rc.APPLICANT_NAME), + safeValue(rc.TYPE_OF_ROAD), + safeValue(rc.ROAD_DEPTH) + ); + } catch (Exception e) { + e.printStackTrace(); // shows exact SQL error + } + } + } + + // TNEB & Metro Water + + public List> getRoadCutList(String loginid) { + String sql = "SELECT " + + " rcd.*, " + + " CASE " + + " WHEN rcd.NOC_STATUS = 'NOC Pending' THEN 1 " + + " WHEN rcd.NOC_STATUS = 'NOC Approved' THEN 2 " + + " ELSE 0 " + + " END AS NOC_STATUS_CODE, " + + " IFNULL(rcs.status, 'new') AS status " + + "FROM " + + " road_cut_details rcd " + + "LEFT JOIN ( " + + " SELECT * " + + " FROM road_cut_status rcs1 " + + " WHERE rcs1.id IN ( " + + " SELECT MAX(id) " + + " FROM road_cut_status " + + " GROUP BY uid " + + " ) " + + ") rcs ON rcs.uid = rcd.uid " + + "WHERE " + + " rcd.isactive = 1 " + + " AND rcd.isdelete = 0 " + + " AND rcd.PAYMENT_STATUS = 'Payment Done' " + + " AND rcd.NOC_STATUS IS NOT NULL " + + " AND IFNULL(rcs.status, 'new') <> 'completed'"; + + List> result = jdbcRoadCutTemplate.queryForList(sql); + Map response = new HashMap<>(); + if (result.isEmpty()) { + response.put("status", "No Data"); + response.put("message", "No road cut list found."); + response.put("data", Collections.emptyList()); // or just null + } else { + response.put("status", "Success"); + response.put("message", "RoadCut List."); + response.put("data", result); + } + + return Collections.singletonList(response); + } + + public List> getLoactionCheck(String loginid, String refid, String streetid, String streetname) { + String sql = "SELECT " + + " rcd.*, " + + " CASE " + + " WHEN rcd.NOC_STATUS = 'NOC Pending' THEN 1 " + + " WHEN rcd.NOC_STATUS = 'NOC Approved' THEN 2 " + + " ELSE 0 " + + " END AS NOC_STATUS_CODE, " + + " IFNULL(rcs.status, 'new') AS status " + + "FROM " + + " road_cut_details rcd " + + "LEFT JOIN ( " + + " SELECT * " + + " FROM road_cut_status rcs1 " + + " WHERE rcs1.id IN ( " + + " SELECT MAX(id) " + + " FROM road_cut_status " + + " GROUP BY uid " + + " ) " + + ") rcs ON rcs.uid = rcd.uid " + + "WHERE " + + " rcd.isactive = 1 " + + " AND rcd.isdelete = 0 " + + " AND rcd.PAYMENT_STATUS = 'Payment Done' " + + " AND rcd.NOC_STATUS IS NOT NULL " + + " AND rcd.UNIQUEID = ? " + + " AND rcd.STREET = ?"; + + List> result = jdbcRoadCutTemplate.queryForList(sql,refid,streetname); + Map response = new HashMap<>(); + + if (result.isEmpty()) { + response.put("status", "False"); + response.put("message", "No road cut details found for the given criteria."); + } else { + response.put("status", "True"); + response.put("message", "Road cut found."); + } + + return Collections.singletonList(response); + } + + public List> getRoadCutDetails(String loginid, String refid) { + String sql = "SELECT rcd.*, IFNULL(rcs.status, 'new') AS status " + + "FROM road_cut_details rcd " + + "LEFT JOIN ( " + + " SELECT * FROM road_cut_status rcs1 " + + " WHERE rcs1.id IN ( " + + " SELECT MAX(id) FROM road_cut_status GROUP BY uid " + + " ) " + + ") rcs ON rcs.uid = rcd.uid " + + "WHERE rcd.isactive = 1 " + + "AND rcd.isdelete = 0 " + + "AND rcd.PAYMENT_STATUS = 'Payment Done' " + + "AND rcd.NOC_STATUS IS NOT NULL " + + "AND rcd.UNIQUEID = ? " + + "AND IFNULL(rcs.status, 'new') <> 'completed'"; + + List> result = jdbcRoadCutTemplate.queryForList(sql, refid); + + for (Map roadCut : result) { + String uid = String.valueOf(roadCut.get("uid")); + + String statusSql = "SELECT id, uid, " + + " DATE_FORMAT(indate, '%d-%m-%Y %I:%i %p') AS indate, " + + "inby, status, " + + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files', filepath) AS filepath, " + + " action, isactive, " + + "latitude, longitude, zone, ward, streetid, streetname, nocid " + + "FROM road_cut_status WHERE uid = ? ORDER BY id ASC"; + + List> statusList = jdbcRoadCutTemplate.queryForList(statusSql, uid); + + List> nocList = new ArrayList<>(); + Map nocEntry = null; + int count = 1; + + for (Map statusRow : statusList) { + String action = String.valueOf(statusRow.get("action")).toLowerCase(); + + if ("before".equals(action)) { + // Save existing 'before' if it had no 'after' + if (nocEntry != null) { + nocEntry.put("after_date", null); + nocEntry.put("after_image", null); + nocEntry.put("after_status", null); + nocEntry.put("after_latitude", null); + nocEntry.put("after_longitude", null); + nocEntry.put("after_zone", null); + nocEntry.put("after_ward", null); + nocEntry.put("NOC_LINK", null); + nocList.add(nocEntry); + count++; + } + + nocEntry = new LinkedHashMap<>(); + nocEntry.put("name", "NOC - " + count); + nocEntry.put("before_date", statusRow.get("indate")); + nocEntry.put("before_image", statusRow.get("filepath")); + nocEntry.put("before_status", statusRow.get("status")); + nocEntry.put("before_latitude", statusRow.get("latitude")); + nocEntry.put("before_longitude", statusRow.get("longitude")); + nocEntry.put("before_zone", statusRow.get("zone")); + nocEntry.put("before_ward", statusRow.get("ward")); + nocEntry.put("NOC_ID", statusRow.get("nocid")); + + } else if ("after".equals(action) && nocEntry != null) { + nocEntry.put("after_date", statusRow.get("indate")); + nocEntry.put("after_image", statusRow.get("filepath")); + nocEntry.put("after_status", statusRow.get("status")); + nocEntry.put("after_latitude", statusRow.get("latitude")); + nocEntry.put("after_longitude", statusRow.get("longitude")); + nocEntry.put("after_zone", statusRow.get("zone")); + nocEntry.put("after_ward", statusRow.get("ward")); + + nocEntry.put("NOC_LINK", statusRow.get("filepath")); + + nocList.add(nocEntry); + nocEntry = null; + count++; + } + } + + // Final unmatched 'before' + if (nocEntry != null) { + nocEntry.put("after_date", null); + nocEntry.put("after_image", null); + nocEntry.put("after_status", null); + nocEntry.put("after_latitude", null); + nocEntry.put("after_longitude", null); + nocEntry.put("after_zone", null); + nocEntry.put("after_ward", null); + nocEntry.put("NOC_LINK", null); + nocList.add(nocEntry); + } + + roadCut.put("NOC_LIST", nocList); + } + + Map response = new HashMap<>(); + if (result.isEmpty()) { + response.put("status", "No Data"); + response.put("message", "No road cut details found for the given refid (" + refid + ")."); + response.put("data", Collections.emptyList()); + } else { + response.put("status", "Success"); + response.put("message", "RoadCut Details."); + response.put("data", result); + } + + return Collections.singletonList(response); + } + + @Transactional + public List> saveStatusUpdate( + String uid, + String cby, + String latitude, + String longitude, + String zone, + String ward, + String streetid, + String streetname, + String action, + String workstatus, + String remarks, + String nocid, + MultipartFile filedata) { + + Map response = new HashMap<>(); + List> result = new ArrayList<>(); + + try { + // Step 1: Get last action for the given uid + String checkSql = "SELECT action, status FROM road_cut_status " + + "WHERE uid = ? ORDER BY id DESC LIMIT 1"; + + String lastAction = null; + String lastStatus = null; + try { + //lastAction = jdbcRoadCutTemplate.queryForObject(checkSql, new Object[]{uid}, String.class); + Map lastRow = jdbcRoadCutTemplate.queryForMap(checkSql, uid); + lastAction = (String) lastRow.get("action"); + lastStatus = (String) lastRow.get("status"); + } catch (EmptyResultDataAccessException e) { + // No previous entry — lastAction stays null + } + + // Step 2: Logic check + if("completed".equalsIgnoreCase(lastStatus)) { + response.put("status", "error"); + response.put("message", "Cannot update ‘after’ or `before` status — This action is already completed"); + result.add(response); + return result; + } + + if ("after".equalsIgnoreCase(action)) { + if (!"before".equalsIgnoreCase(lastAction)) { + response.put("status", "error"); + response.put("message", "Cannot upload ‘after’ status — please upload a ‘before’ status first."); + result.add(response); + return result; + } + } else if ("before".equalsIgnoreCase(action)) { + if ("before".equalsIgnoreCase(lastAction)) { + response.put("status", "error"); + response.put("message", "'Before' already exists. You cannot insert it again before 'after'."); + result.add(response); + return result; + } + } + + // Step 3: Upload file + String actionimg = fileUpload("other_"+uid, action, filedata); + + // Step 4: Insert data + + // Before Create new NOC + if ("before".equalsIgnoreCase(action)) { + String insertNOCSql = "INSERT INTO `road_cut_noc_list`(`uid`, `other_before`) VALUES (?,?)"; + KeyHolder keyHolder_noc = new GeneratedKeyHolder(); + int affectedRows_noc = jdbcRoadCutTemplate.update(connection -> { + PreparedStatement ps_noc = connection.prepareStatement(insertNOCSql, new String[]{"nocid"}); + int i = 1; + ps_noc.setString(i++, uid); + ps_noc.setInt(i++, 1); + return ps_noc; + }, keyHolder_noc); + + if (affectedRows_noc > 0) { + int nocInsertId = keyHolder_noc.getKey().intValue(); + nocid=""+nocInsertId; + } else { + response.put("status", "error"); + response.put("message", "'NOC - Insert `before` failed."); + result.add(response); + return result; + } + } + + String noc_id = nocid; + + // Update After NOC + if ("after".equalsIgnoreCase(action)) { + String updateNOCSql = "UPDATE `road_cut_noc_list` SET `other_after`=? WHERE `nocid`=?"; + int affectedRowsNOC = jdbcRoadCutTemplate.update(updateNOCSql, 1, nocid); + + if (affectedRowsNOC > 0) { + + } else { + response.put("status", "error"); + response.put("message", "NOC - Update 'after' failed."); + result.add(response); + return result; + } + } + + String insertSql = "INSERT INTO road_cut_status " + + "(uid, inby, latitude, longitude, zone, ward, streetid, streetname, " + + "status, filepath, action, isactive, nocid) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + KeyHolder keyHolder = new GeneratedKeyHolder(); + int affectedRows = jdbcRoadCutTemplate.update(connection -> { + PreparedStatement ps = connection.prepareStatement(insertSql, new String[]{"id"}); + int i = 1; + ps.setString(i++, uid); + ps.setString(i++, cby); + ps.setString(i++, latitude); + ps.setString(i++, longitude); + ps.setString(i++, zone); + ps.setString(i++, ward); + ps.setString(i++, streetid); + ps.setString(i++, streetname); + ps.setString(i++, workstatus); + ps.setString(i++, actionimg); + ps.setString(i++, action); + ps.setInt(i++, 1); + ps.setString(i++, noc_id); + return ps; + }, keyHolder); + + if (affectedRows > 0) { + int lastInsertId = keyHolder.getKey().intValue(); + response.put("insertId", lastInsertId); + response.put("status", "success"); + response.put("message", "Status update inserted successfully."); + } else { + response.put("status", "error"); + response.put("message", "Insert failed."); + } + + } catch (Exception e) { + response.put("status", "error"); + response.put("message", "Exception occurred: " + e.getMessage()); + e.printStackTrace(); + } + + result.add(response); + return result; + } + + /////// ********************************************************** /////// + + // AE GCC Officer + + public List> getRoadCutList_offical(String loginid) { + String sql = "SELECT " + + " rcd.*, " + + " CASE " + + " WHEN rcd.NOC_STATUS = 'NOC Pending' THEN 1 " + + " WHEN rcd.NOC_STATUS = 'NOC Approved' THEN 2 " + + " ELSE 0 " + + " END AS NOC_STATUS_CODE, " + + " status_summary.status " + + "FROM road_cut_details rcd " + + "JOIN ( " + + " SELECT " + + " noc.uid, " + + " CASE " + + " WHEN SUM(CASE WHEN noc.gcc_before != 1 OR noc.gcc_after != 1 THEN 1 ELSE 0 END) > 0 THEN 'pending' " + + " ELSE 'completed' " + + " END AS status " + + " FROM road_cut_noc_list noc " + + " WHERE noc.isactive = 1 AND noc.other_before = 1 AND noc.other_after = 1 " + + " GROUP BY noc.uid " + + ") AS status_summary " + + "ON rcd.uid = status_summary.uid " + + "WHERE " + + " rcd.isactive = 1 " + + " AND rcd.isdelete = 0 " + + " AND rcd.PAYMENT_STATUS = 'Payment Done' " + + " AND rcd.NOC_STATUS IS NOT NULL " + + "ORDER BY rcd.uid"; + + List> result = jdbcRoadCutTemplate.queryForList(sql); + Map response = new HashMap<>(); + if (result.isEmpty()) { + response.put("status", "No Data"); + response.put("message", "No officer road cut list found."); + response.put("data", Collections.emptyList()); // or just null + } else { + response.put("status", "Success"); + response.put("message", "Officer RoadCut List."); + response.put("data", result); + } + + return Collections.singletonList(response); + } + + public List> getLoactionCheck_offical(String loginid, String refid, String streetid, String streetname) { + String sql = "SELECT " + + " rcd.*, " + + " CASE " + + " WHEN rcd.NOC_STATUS = 'NOC Pending' THEN 1 " + + " WHEN rcd.NOC_STATUS = 'NOC Approved' THEN 2 " + + " ELSE 0 " + + " END AS NOC_STATUS_CODE, " + + " IFNULL(rcs.status, 'new') AS status " + + "FROM " + + " road_cut_details rcd " + + "LEFT JOIN ( " + + " SELECT * " + + " FROM road_cut_status rcs1 " + + " WHERE rcs1.id IN ( " + + " SELECT MAX(id) " + + " FROM road_cut_status " + + " GROUP BY uid " + + " ) " + + ") rcs ON rcs.uid = rcd.uid " + + "WHERE " + + " rcd.isactive = 1 " + + " AND rcd.isdelete = 0 " + + " AND rcd.PAYMENT_STATUS = 'Payment Done' " + + " AND rcd.NOC_STATUS IS NOT NULL " + + " AND rcd.UNIQUEID = ? " + + " AND rcd.STREET = ?"; + + List> result = jdbcRoadCutTemplate.queryForList(sql,refid,streetname); + Map response = new HashMap<>(); + + if (result.isEmpty()) { + response.put("status", "False"); + response.put("message", "No road cut details found for the given criteria."); + } else { + response.put("status", "True"); + response.put("message", "Road cut found."); + } + + return Collections.singletonList(response); + } + + public List> getRoadCutDetails_offical(String loginid, String refid) { + String sql = "SELECT rcd.*, IFNULL(rcs.status, 'new') AS status " + + "FROM road_cut_details rcd " + + "LEFT JOIN ( " + + " SELECT * FROM road_cut_status rcs1 " + + " WHERE rcs1.id IN ( " + + " SELECT MAX(id) FROM road_cut_status GROUP BY uid " + + " ) " + + ") rcs ON rcs.uid = rcd.uid " + + "WHERE rcd.isactive = 1 " + + "AND rcd.isdelete = 0 " + + "AND rcd.PAYMENT_STATUS = 'Payment Done' " + + "AND rcd.NOC_STATUS IS NOT NULL " + + "AND rcd.UNIQUEID = ?"; + + List> result = jdbcRoadCutTemplate.queryForList(sql, refid); + + for (Map roadCut : result) { + String uid = String.valueOf(roadCut.get("uid")); + + String statusSql = "SELECT `nocid`, `uid`, `other_before`, `other_after`, " + + "`gcc_before`, `gcc_after`, `noc_file` " + + "FROM `road_cut_noc_list` " + + "WHERE uid=? AND `isactive`=1 " + + "ORDER BY `nocid` ASC"; + + List> statusList = jdbcRoadCutTemplate.queryForList(statusSql, uid); + List> nocList = new ArrayList<>(); + + for (Map statusRow : statusList) { + String nocid = String.valueOf(statusRow.get("nocid")); + + String formattedStatusSql = "SELECT id, uid, " + + "DATE_FORMAT(indate, '%d-%m-%Y %I:%i %p') AS indate, " + + "inby, status, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', filepath) AS filepath, " + + "action, isactive, latitude, longitude, zone, ward, streetid, streetname, nocid " + + "FROM road_cut_status " + + "WHERE uid = ? AND nocid = ? " + + "ORDER BY id ASC"; + + List> formattedList = jdbcRoadCutTemplate.queryForList(formattedStatusSql, uid, nocid); + + String statusNOCSql = "SELECT id, uid, " + + "DATE_FORMAT(indate, '%d-%m-%Y %I:%i %p') AS indate, " + + "inby, status, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', filepath) AS filepath, " + + "action, isactive, latitude, longitude, zone, ward, streetid, streetname, nocid " + + "FROM road_cut_officer_status " + + "WHERE uid = ? AND nocid = ? " + + "ORDER BY id ASC"; + + List> officerList = jdbcRoadCutTemplate.queryForList(statusNOCSql, uid, nocid); + + Map nocEntry = new LinkedHashMap<>(); + nocEntry.put("name", "NOC - " + nocid); + nocEntry.put("NOC_ID", nocid); + + // 🟩 Add default nulls for officer_* fields + nocEntry.put("officer_before_date", null); + nocEntry.put("officer_before_image", null); + nocEntry.put("officer_before_status", null); + nocEntry.put("officer_before_latitude", null); + nocEntry.put("officer_before_longitude", null); + nocEntry.put("officer_before_zone", null); + nocEntry.put("officer_before_ward", null); + nocEntry.put("officer_after_date", null); + nocEntry.put("officer_after_image", null); + nocEntry.put("officer_after_status", null); + nocEntry.put("officer_after_latitude", null); + nocEntry.put("officer_after_longitude", null); + nocEntry.put("officer_after_zone", null); + nocEntry.put("officer_after_ward", null); + + // Add formatted (app) status + for (Map formattedRow : formattedList) { + String action = String.valueOf(formattedRow.get("action")).trim().toLowerCase(); + if ("before".equals(action)) { + nocEntry.put("before_date", formattedRow.get("indate")); + nocEntry.put("before_image", formattedRow.get("filepath")); + nocEntry.put("before_status", formattedRow.get("status")); + nocEntry.put("before_latitude", formattedRow.get("latitude")); + nocEntry.put("before_longitude", formattedRow.get("longitude")); + nocEntry.put("before_zone", formattedRow.get("zone")); + nocEntry.put("before_ward", formattedRow.get("ward")); + } else if ("after".equals(action)) { + nocEntry.put("after_date", formattedRow.get("indate")); + nocEntry.put("after_image", formattedRow.get("filepath")); + nocEntry.put("after_status", formattedRow.get("status")); + nocEntry.put("after_latitude", formattedRow.get("latitude")); + nocEntry.put("after_longitude", formattedRow.get("longitude")); + nocEntry.put("after_zone", formattedRow.get("zone")); + nocEntry.put("after_ward", formattedRow.get("ward")); + nocEntry.put("NOC_LINK", formattedRow.get("filepath")); + } + } + + // Add officer_* if available + for (Map officerRow : officerList) { + System.out.println("I am IN "+officerRow.get("id")); + String action = String.valueOf(officerRow.get("action")).trim().toLowerCase(); + if ("before".equals(action)) { + nocEntry.put("officer_before_date", officerRow.get("indate")); + nocEntry.put("officer_before_image", officerRow.get("filepath")); + nocEntry.put("officer_before_status", officerRow.get("status")); + nocEntry.put("officer_before_latitude", officerRow.get("latitude")); + nocEntry.put("officer_before_longitude", officerRow.get("longitude")); + nocEntry.put("officer_before_zone", officerRow.get("zone")); + nocEntry.put("officer_before_ward", officerRow.get("ward")); + } else if ("after".equals(action)) { + nocEntry.put("officer_after_date", officerRow.get("indate")); + nocEntry.put("officer_after_image", officerRow.get("filepath")); + nocEntry.put("officer_after_status", officerRow.get("status")); + nocEntry.put("officer_after_latitude", officerRow.get("latitude")); + nocEntry.put("officer_after_longitude", officerRow.get("longitude")); + nocEntry.put("officer_after_zone", officerRow.get("zone")); + nocEntry.put("officer_after_ward", officerRow.get("ward")); + //nocEntry.put("NOC_LINK", officerRow.get("filepath")); // fallback + } + } + + nocList.add(nocEntry); + } + + roadCut.put("NOC_LIST", nocList); + } + + Map response = new HashMap<>(); + if (result.isEmpty()) { + response.put("status", "No Data"); + response.put("message", "No road cut details found for the given refid (" + refid + ")."); + response.put("data", Collections.emptyList()); + } else { + response.put("status", "Success"); + response.put("message", "RoadCut Details."); + response.put("data", result); + } + + return Collections.singletonList(response); + } + + @Transactional + public List> saveStatusUpdate_offical( + String uid, + String cby, + String latitude, + String longitude, + String zone, + String ward, + String streetid, + String streetname, + String action, + String workstatus, + String remarks, + String nocid, + MultipartFile filedata) { + + Map response = new HashMap<>(); + List> result = new ArrayList<>(); + + try { + // Step 1: Get last action for the given uid + String checkSql = "SELECT action, status FROM `road_cut_officer_status` " + + "WHERE uid = ? AND nocid = ? ORDER BY id DESC LIMIT 1"; + + String lastAction = null; + String lastStatus = null; + try { + //lastAction = jdbcRoadCutTemplate.queryForObject(checkSql, new Object[]{uid}, String.class); + Map lastRow = jdbcRoadCutTemplate.queryForMap(checkSql, uid, nocid); + lastAction = (String) lastRow.get("action"); + lastStatus = (String) lastRow.get("status"); + } catch (EmptyResultDataAccessException e) { + // No previous entry — lastAction stays null + } + + // Step 2: Logic check + if("completed".equalsIgnoreCase(lastStatus)) { + response.put("status", "error"); + response.put("message", "Officer - Cannot update ‘after’ or `before` status — This action is already completed"); + result.add(response); + return result; + } + + if ("after".equalsIgnoreCase(action)) { + if (!"before".equalsIgnoreCase(lastAction)) { + response.put("status", "error"); + response.put("message", "Cannot upload ‘after’ status — please upload a ‘before’ status first."); + result.add(response); + return result; + } + } else if ("before".equalsIgnoreCase(action)) { + if ("before".equalsIgnoreCase(lastAction)) { + response.put("status", "error"); + response.put("message", "'Before' already exists. You cannot insert it again before 'after'."); + result.add(response); + return result; + } + } + + // Step 3: Upload file + String actionimg = fileUpload("officer_"+uid, action, filedata); + + // Step 4: Insert data + + // Update before NOC + if ("before".equalsIgnoreCase(action)) { + String updateNOCSql = "UPDATE `road_cut_noc_list` SET `gcc_before`=? WHERE `nocid`=?"; + int affectedRowsNOC = jdbcRoadCutTemplate.update(updateNOCSql, 1, nocid); + + if (affectedRowsNOC > 0) { + + } else { + response.put("status", "error"); + response.put("message", "Oficer NOC - Update 'before' failed."); + result.add(response); + return result; + } + } + + // Update After NOC + if ("after".equalsIgnoreCase(action)) { + String updateNOCSql = "UPDATE `road_cut_noc_list` SET `gcc_after`=? WHERE `nocid`=?"; + int affectedRowsNOC = jdbcRoadCutTemplate.update(updateNOCSql, 1, nocid); + + if (affectedRowsNOC > 0) { + + } else { + response.put("status", "error"); + response.put("message", "Oficer NOC - Update 'after' failed."); + result.add(response); + return result; + } + } + + String insertSql = "INSERT INTO road_cut_officer_status " + + "(uid, inby, latitude, longitude, zone, ward, streetid, streetname, " + + "status, filepath, action, isactive, nocid) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + KeyHolder keyHolder = new GeneratedKeyHolder(); + int affectedRows = jdbcRoadCutTemplate.update(connection -> { + PreparedStatement ps = connection.prepareStatement(insertSql, new String[]{"id"}); + int i = 1; + ps.setString(i++, uid); + ps.setString(i++, cby); + ps.setString(i++, latitude); + ps.setString(i++, longitude); + ps.setString(i++, zone); + ps.setString(i++, ward); + ps.setString(i++, streetid); + ps.setString(i++, streetname); + ps.setString(i++, workstatus); + ps.setString(i++, actionimg); + ps.setString(i++, action); + ps.setInt(i++, 1); + ps.setString(i++, nocid); + return ps; + }, keyHolder); + + if (affectedRows > 0) { + int lastInsertId = keyHolder.getKey().intValue(); + response.put("insertId", lastInsertId); + response.put("status", "success"); + response.put("message", "Officer Status update inserted successfully."); + } else { + response.put("status", "error"); + response.put("message", "Officer Insert failed."); + } + + } catch (Exception e) { + response.put("status", "error"); + response.put("message", "Exception occurred: " + e.getMessage()); + e.printStackTrace(); + } + + result.add(response); + return result; + } +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/roadcut/service/package-info.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/roadcut/service/package-info.java new file mode 100644 index 0000000..b566eef --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/roadcut/service/package-info.java @@ -0,0 +1 @@ +package in.gov.chennaicorporation.mobileservice.roadcut.service; \ No newline at end of file diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/service/OfficialAPIService.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/service/OfficialAPIService.java index ed393ab..2c05779 100644 --- a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/service/OfficialAPIService.java +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/service/OfficialAPIService.java @@ -59,20 +59,23 @@ public class OfficialAPIService { } public List> sendOTP(HttpServletRequest request, - @RequestParam("MobileNo") String MobileNo, - @RequestParam("generatedToken") String OTP) { + String MobileNo, + String OTP, + String checkmobileno + ) { Boolean sendSMS = true; Map successResponse =null; - if(getUserListByMobileNumber(MobileNo).size()<=0) - { - sendSMS = false; - successResponse = Map.of( - "status", 404, - "message", "Given mobile number “"+MobileNo+"” is not registered." - ); + if (!"false".equalsIgnoreCase(checkmobileno)) { + if(getUserListByMobileNumber(MobileNo).size()<=0) + { + sendSMS = false; + successResponse = Map.of( + "status", 404, + "message", "Given mobile number “"+MobileNo+"” is not registered." + ); + } } - if(sendSMS) { //Integer OTP = OTP; String generatedToken = "Your OTP is " + OTP + ".OTP is valid for the next 5 minutes.\nBy\nGreater Chennai Corporation."; diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/service/PdfGeneratorService.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/service/PdfGeneratorService.java new file mode 100644 index 0000000..cdc58fd --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/service/PdfGeneratorService.java @@ -0,0 +1,42 @@ +package in.gov.chennaicorporation.mobileservice.service; + +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.thymeleaf.TemplateEngine; +import org.thymeleaf.context.Context; + +import com.openhtmltopdf.pdfboxout.PdfRendererBuilder; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.time.LocalDate; +import java.util.Map; + +@Service +public class PdfGeneratorService { + @Autowired + private TemplateEngine templateEngine; + + public byte[] generatePdf(Map data) { + Context context = new Context(); + context.setVariables(data); + + String htmlContent = templateEngine.process("pdf-template", context); + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + PdfRendererBuilder builder = new PdfRendererBuilder(); + builder.useFastMode(); + builder.withHtmlContent(htmlContent, null); + builder.toStream(os); + try { + builder.run(); + } catch (IOException e) { + e.printStackTrace(); // or log it properly + throw new RuntimeException("PDF generation failed", e); + } + + return os.toByteArray(); + } +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/speedbrake/controller/APIController.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/speedbrake/controller/APIController.java new file mode 100644 index 0000000..68c2df2 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/speedbrake/controller/APIController.java @@ -0,0 +1,93 @@ +package in.gov.chennaicorporation.mobileservice.speedbrake.controller; + +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import in.gov.chennaicorporation.mobileservice.speedbrake.service.APIService; + +@RequestMapping("/gccofficialapp/api/speedbrake/") +@RestController("gccofficialappsspeedbrake") +public class APIController { + @Autowired + private APIService apiService; + + @GetMapping(value="/getQuestions") + public List getQuestions(){ + return apiService.getQuestions(); + } + + @GetMapping(value="/checkAssetExists") + public List checkAssetExists( + @RequestParam(value = "latitude", required = true) String latitude, + @RequestParam(value = "longitude", required = true) String longitude + ){ + return apiService.checkAssetExists(latitude,longitude); + } + + @PostMapping(value="/saveSpeedBrakeDetails") + public List> saveConstructionDetails( + @RequestParam(value = "zone", required = true) String zone, + @RequestParam(value = "ward", required = true) String ward, + @RequestParam(value = "streetid", required = true) String streetid, + @RequestParam(value = "streetname", required = true) String streetname, + @RequestParam(value = "streettype", required = true) String streettype, + @RequestParam(value = "roadtype", required = true) String roadtype, + @RequestParam(value = "marktype", required = true) String marktype, + @RequestParam(value = "q1", required = false) String q1, + @RequestParam(value = "q2", required = false) String q2, + @RequestParam(value = "q3", required = false) String q3, + @RequestParam(value = "cby", required = true) String cby, + @RequestParam(value = "latitude", required = true) String latitude, + @RequestParam(value = "longitude", required = true) String longitude, + @RequestParam(value = "sb_condition", required = false) String sb_condition, + @RequestParam(value = "mainfile", required = true) MultipartFile mainFile + ){ + return apiService.saveSpeedBrakeDetails( + zone, ward, streetid, streetname, streettype, + roadtype, marktype, q1, q2, q3, cby, latitude, longitude, sb_condition, mainFile + ); + } + + // 1. Zone-wise report + @GetMapping("/zone-wise") + public List> getZoneWiseReport() { + return apiService.getZoneWiseReport(); + } + + // 2. Ward-wise report by zone + @GetMapping("/ward-wise") + public List> getWardWiseReport(@RequestParam String zone) { + return apiService.getWardeWiseReport(zone); + } + + // 3. Street-wise report (New) by ward + @GetMapping("/new-street-wise") + public List> getNewStreetWiseReport(@RequestParam String ward) { + return apiService.getNewStreetWiseReport(ward); + } + + // 4. Street-wise report (Existing) by ward + @GetMapping("/existing-street-wise") + public List> getExistingStreetWiseReport(@RequestParam String ward) { + return apiService.getExistingStreetWiseReport(ward); + } + + // 5. Detailed Speedbrake Entry with Q&A + @GetMapping("/details") + public List> getSpeedbrakeDetails( + @RequestParam String ward, + @RequestParam String streetname, + @RequestParam String marktype, + @RequestParam(required = false) String sb_condition + ) { + return apiService.getSpeedbrakeDetailsWithQuestions(ward, marktype, sb_condition, streetname); + } +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/speedbrake/controller/package-info.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/speedbrake/controller/package-info.java new file mode 100644 index 0000000..58eec05 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/speedbrake/controller/package-info.java @@ -0,0 +1 @@ +package in.gov.chennaicorporation.mobileservice.speedbrake.controller; \ No newline at end of file diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/speedbrake/package-info.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/speedbrake/package-info.java new file mode 100644 index 0000000..da706ce --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/speedbrake/package-info.java @@ -0,0 +1 @@ +package in.gov.chennaicorporation.mobileservice.speedbrake; \ No newline at end of file diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/speedbrake/service/APIService.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/speedbrake/service/APIService.java new file mode 100644 index 0000000..7f32c9a --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/speedbrake/service/APIService.java @@ -0,0 +1,453 @@ +package in.gov.chennaicorporation.mobileservice.speedbrake.service; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.SecureRandom; +import java.sql.PreparedStatement; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import javax.imageio.ImageIO; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.stream.ImageOutputStream; +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.core.env.Environment; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import in.gov.chennaicorporation.mobileservice.gccactivity.service.DateTimeUtil; + +@Service +public class APIService { + + private JdbcTemplate jdbcSpeedBrake; + private final Environment environment; + private String fileBaseUrl; + + private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + private static final int STRING_LENGTH = 15; + private static final Random RANDOM = new SecureRandom(); + + @Autowired + public void setDataSource(@Qualifier("mysqlGccSpeedBrakeSource") DataSource speedBrakeDataSource) { + this.jdbcSpeedBrake = new JdbcTemplate(speedBrakeDataSource); + } + + @Autowired + public APIService(Environment environment) { + this.environment = environment; + this.fileBaseUrl=environment.getProperty("fileBaseUrl"); + } + + public static String generateRandomString() { + StringBuilder result = new StringBuilder(STRING_LENGTH); + for (int i = 0; i < STRING_LENGTH; i++) { + result.append(CHARACTERS.charAt(RANDOM.nextInt(CHARACTERS.length()))); + } + return result.toString(); + } + + public static String generateRandomFileString(int lenthval) { + StringBuilder result = new StringBuilder(lenthval); + for (int i = 0; i < lenthval; i++) { + result.append(CHARACTERS.charAt(RANDOM.nextInt(CHARACTERS.length()))); + } + return result.toString(); + } + + private byte[] compressImage(BufferedImage image, float quality) throws IOException { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(byteArrayOutputStream); + + ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next(); + writer.setOutput(imageOutputStream); + + ImageWriteParam param = writer.getDefaultWriteParam(); + if (param.canWriteCompressed()) { + param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); + param.setCompressionQuality(quality); + } + + writer.write(null, new javax.imageio.IIOImage(image, null, null), param); + + writer.dispose(); + imageOutputStream.close(); + + return byteArrayOutputStream.toByteArray(); + } + + public String fileUpload(String name, String id, MultipartFile file) { + + int lastInsertId = 0; + // Set the file path where you want to save it + String uploadDirectory = environment.getProperty("file.upload.directory"); + String serviceFolderName = environment.getProperty("speedbrake_foldername"); + var year = DateTimeUtil.getCurrentYear(); + var month = DateTimeUtil.getCurrentMonth(); + var date = DateTimeUtil.getCurrentDay(); + + uploadDirectory = uploadDirectory + serviceFolderName + year + "/" + month + "/" + date; + + try { + // Create directory if it doesn't exist + Path directoryPath = Paths.get(uploadDirectory); + if (!Files.exists(directoryPath)) { + Files.createDirectories(directoryPath); + } + + // Datetime string + String datetimetxt = DateTimeUtil.getCurrentDateTime(); + + datetimetxt = datetimetxt + "_"+ generateRandomFileString(6); // Attached Random text + + // File name + String fileName = name + "_" + id + "_" + datetimetxt + "_" + file.getOriginalFilename(); + fileName = fileName.replaceAll("\\s+", ""); // Remove space on filename + + String filePath = uploadDirectory + "/" + fileName; + + String filepath_txt = "/" + serviceFolderName + year + "/" + month + "/" + date + "/" + fileName; + + // Create a new Path object + Path path = Paths.get(filePath); + + // Get the bytes of the file + byte[] bytes = file.getBytes(); + + // Compress the image + BufferedImage image = ImageIO.read(new ByteArrayInputStream(bytes)); + byte[] compressedBytes = compressImage(image, 0.5f); // Compress with 50% quality + + // Write the bytes to the file + Files.write(path, compressedBytes); + + System.out.println(filePath); + return filepath_txt; + + } catch (IOException e) { + e.printStackTrace(); + return "Failed to save file " + file.getOriginalFilename(); + } + } + + public List> getQuestions(){ + String sql = "SELECT * FROM `Questions` WHERE `isactive`=1 ORDER BY `orderby`"; + List> result = jdbcSpeedBrake.queryForList(sql); + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "Question List."); + response.put("data", result); + + return Collections.singletonList(response); + } + + @Transactional + public List> checkAssetExists(String latitudeStr, String longitudeStr) { + double latitude = Double.parseDouble(latitudeStr); + double longitude = Double.parseDouble(longitudeStr); + + String checkSql = "SELECT COUNT(*) FROM speedbrake_list sbl " + + "WHERE (6371008.8 * ACOS(COS(RADIANS(?)) * COS(RADIANS(sbl.latitude)) * " + + "COS(RADIANS(sbl.longitude) - RADIANS(?)) + SIN(RADIANS(?)) * SIN(RADIANS(sbl.latitude)))) < 2"; + //Integer count = jdbcSpeedBrake.queryForObject(checkSql,new Object[]{latitude, longitude, latitude}, Integer.class); + + Integer count = jdbcSpeedBrake.queryForObject( + checkSql, + Integer.class, + latitude, longitude, latitude + ); + + Map response = new HashMap<>(); + if (count != null && count > 0) { + response.put("count", count); + response.put("status", "error"); + response.put("message", "Duplicate: Speed breaker already exists."); + } else { + response.put("count", count); + response.put("status", "success"); + response.put("message", "No existing speed breaker found."); + } + return Collections.singletonList(response); + } + + @Transactional + public List> saveSpeedBrakeDetails( + String zone, + String ward, + String streetid, + String streetname, + String streettype, + String roadtype, + String marktype, + String q1, + String q2, + String q3, + String cby, + String latitude, + String longitude, + String sb_condition, + MultipartFile mainfile + ) { + Map response = new HashMap<>(); + List> result = new ArrayList<>(); + + String roadimg = fileUpload("Construction", "main", mainfile); + + String roadcategorytxt = "GCC"; + + if("HY".equalsIgnoreCase(roadtype)) { + roadcategorytxt = "Highways"; + } + + String roadcategory = roadcategorytxt; + + // Insert query + String insertSql = "INSERT INTO `speedbrake_list`(`zone`, `ward`, `streetid`, `streetname`, `streettype`, `roadcategory`, " + + "`roadtype`, `marktype`, `file`, " + + "`q1`, `q2`, `q3`, `cby`,`latitude`, `longitude`,`sb_condition`) VALUES " + + "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; + + KeyHolder keyHolder = new GeneratedKeyHolder(); + + int affectedRows = jdbcSpeedBrake.update(connection -> { + PreparedStatement ps = connection.prepareStatement(insertSql, new String[]{"cdid"}); + int i = 1; + ps.setString(i++, zone); + ps.setString(i++, ward); + ps.setString(i++, streetid); + ps.setString(i++, streetname); + ps.setString(i++, streettype); + ps.setString(i++, roadcategory); + ps.setString(i++, roadtype); + ps.setString(i++, marktype); + ps.setString(i++, roadimg); + ps.setString(i++, q1); + ps.setString(i++, q2); + ps.setString(i++, q3); + ps.setString(i++, cby); + ps.setString(i++, latitude); + ps.setString(i++, longitude); + ps.setString(i++, sb_condition); + + return ps; + }, keyHolder); + + if (affectedRows > 0) { + int lastInsertId = keyHolder.getKey().intValue(); + + response.put("insertId", lastInsertId); + response.put("status", "success"); + response.put("message", "Speed Brake details inserted successfully."); + + + } else { + response.put("status", "error"); + response.put("message", "Speed Brake details insert failed."); + } + + result.add(response); + return result; + } + + public List> getZoneWiseReport() { + String sql = "SELECT " + + " zone, " + + " COUNT(*) AS total_mapping, " + + " SUM(CASE WHEN marktype = 'New' THEN 1 ELSE 0 END) AS new_count, " + + " SUM(CASE WHEN marktype = 'Existing' THEN 1 ELSE 0 END) AS existing_count " + + "FROM " + + " speedbrake_list " + + "WHERE " + + " isactive = 1 AND isdelete = 0 " + + "GROUP BY " + + " zone " + + " " + + "UNION ALL " + + " " + + "SELECT " + + " 'Total' AS zone, " + + " COUNT(*) AS total_mapping, " + + " SUM(CASE WHEN marktype = 'New' THEN 1 ELSE 0 END), " + + " SUM(CASE WHEN marktype = 'Existing' THEN 1 ELSE 0 END) " + + "FROM " + + " speedbrake_list " + + "WHERE " + + " isactive = 1 AND isdelete = 0 " + + " " + + "ORDER BY " + + " CASE " + + " WHEN zone = 'Total' THEN 1 " + + " ELSE 0 " + + " END, " + + " zone"; + + return jdbcSpeedBrake.queryForList(sql); + } + + public List> getWardeWiseReport(String zone) { + String sql = "SELECT " + + " ward, " + + " COUNT(*) AS total_mapping, " + + " SUM(CASE WHEN marktype = 'New' THEN 1 ELSE 0 END) AS new_count, " + + " SUM(CASE WHEN marktype = 'Existing' THEN 1 ELSE 0 END) AS existing_count " + + "FROM " + + " speedbrake_list " + + "WHERE " + + " isactive = 1 AND isdelete = 0 AND zone = ? " + + "GROUP BY " + + " ward " + + " " + + "UNION ALL " + + " " + + "SELECT " + + " 'Total' AS ward, " + + " COUNT(*) AS total_mapping, " + + " SUM(CASE WHEN marktype = 'New' THEN 1 ELSE 0 END), " + + " SUM(CASE WHEN marktype = 'Existing' THEN 1 ELSE 0 END) " + + "FROM " + + " speedbrake_list " + + "WHERE " + + " isactive = 1 AND isdelete = 0 AND zone = ? " + + "ORDER BY " + + " CASE " + + " WHEN ward = 'Total' THEN 1 " + + " ELSE 0 " + + " END, " + + " ward"; + + return jdbcSpeedBrake.queryForList(sql,zone,zone); + } + + public List> getNewStreetWiseReport(String ward) { + String sql = "SELECT " + + " streetname, " + + " COUNT(*) AS count " + + "FROM " + + " speedbrake_list " + + "WHERE " + + " isactive = 1 " + + " AND isdelete = 0 " + + " AND marktype = 'New' " + + " AND ward = ? " + + "GROUP BY " + + " streetname " + + " " + + "UNION ALL " + + " " + + "SELECT " + + " 'Total' AS streetname, " + + " COUNT(*) AS count " + + "FROM " + + " speedbrake_list " + + "WHERE " + + " isactive = 1 " + + " AND isdelete = 0 " + + " AND marktype = 'New' " + + " AND ward = ?"; + + return jdbcSpeedBrake.queryForList(sql,ward,ward); + } + + public List> getExistingStreetWiseReport(String ward) { + String sql = "SELECT " + + " streetname, " + + " SUM(CASE WHEN sb_condition = 'Good' THEN 1 ELSE 0 END) AS good_count, " + + " SUM(CASE WHEN sb_condition = 'Complete reconstruction' THEN 1 ELSE 0 END) AS complete_reconstruction_count, " + + " SUM(CASE WHEN sb_condition = 'Improvement to the existing' THEN 1 ELSE 0 END) AS improvement_count " + + "FROM " + + " speedbrake_list " + + "WHERE " + + " isactive = 1 " + + " AND isdelete = 0 " + + " AND marktype = 'Existing' " + + " AND ward = ? " + + "GROUP BY " + + " streetname " + + " " + + "UNION ALL " + + " " + + "SELECT " + + " 'Total' AS streetname, " + + " SUM(CASE WHEN sb_condition = 'Good' THEN 1 ELSE 0 END), " + + " SUM(CASE WHEN sb_condition = 'Complete reconstruction' THEN 1 ELSE 0 END), " + + " SUM(CASE WHEN sb_condition = 'Improvement to the existing' THEN 1 ELSE 0 END) " + + "FROM " + + " speedbrake_list " + + "WHERE " + + " isactive = 1 " + + " AND isdelete = 0 " + + " AND marktype = 'Existing' " + + " AND ward = ?"; + + return jdbcSpeedBrake.queryForList(sql,ward,ward); + } + + public List> getSpeedbrakeDetailsWithQuestions(String ward, String marktype, String sb_condition, String streetname) { + String where = ""; + List params = new ArrayList<>(); + params.add(marktype); + params.add(ward); + params.add(streetname); + + if (sb_condition != null) { + where = " AND sb_condition = ?"; + params.add(sb_condition); + } + + // 1. Fetch questions list + String qSql = "SELECT orderby, english FROM Questions ORDER BY orderby"; + List> questions = jdbcSpeedBrake.queryForList(qSql); + + // 2. Fetch speedbrake entries + String sql = "SELECT id, zone, ward, streetid, streetname, streettype, " + + "roadcategory, roadtype, marktype, q1, q2, q3, q4, cby, cddate, " + + "latitude, longitude, sb_condition, " + + "CONCAT('" + fileBaseUrl + "/gccofficialapp/files', file) AS complaint_image_url " + + "FROM speedbrake_list " + + "WHERE isactive = 1 AND isdelete = 0 AND marktype = ? AND ward = ? AND streetname = ? " + where; + + List> entries = jdbcSpeedBrake.queryForList(sql, params.toArray()); + + // 3. Merge Q&A into each entry + for (Map row : entries) { + List> qnaList = new ArrayList<>(); + + for (int i = 1; i <= 4; i++) { + Object qVal = row.get("q" + i); + if (qVal != null && i <= questions.size()) { + String questionText = String.valueOf(questions.get(i - 1).get("english")); + Map qna = new HashMap<>(); + qna.put("q", questionText); + qna.put("ans", String.valueOf(qVal)); + qnaList.add(qna); + } + } + + row.put("questions", qnaList); + + // Remove q1–q4 from main record + row.remove("q1"); + row.remove("q2"); + row.remove("q3"); + row.remove("q4"); + } + return entries; + } +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/speedbrake/service/package-info.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/speedbrake/service/package-info.java new file mode 100644 index 0000000..49f34ec --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/speedbrake/service/package-info.java @@ -0,0 +1 @@ +package in.gov.chennaicorporation.mobileservice.speedbrake.service; \ No newline at end of file diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/toilets/controller/APIController.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/toilets/controller/APIController.java index f068f03..c224065 100644 --- a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/toilets/controller/APIController.java +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/toilets/controller/APIController.java @@ -25,6 +25,13 @@ public class APIController { return activity.getToiletsList(cby); } + @GetMapping("/toiletlistRest") + public List toiletlistRest(@RequestParam MultiValueMap formData, + @RequestParam(value = "latitude", required = true) String latitude, + @RequestParam(value = "longitude", required = true) String longitude) { + return activity.toiletlistRest(formData, latitude, longitude); + } + @PostMapping(value="/updateToiletLocation") public List updateToiletLocation( @RequestParam(value="loginId", required = true) String cby, diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/toilets/service/activity.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/toilets/service/activity.java index efe0846..706ae36 100644 --- a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/toilets/service/activity.java +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/toilets/service/activity.java @@ -179,6 +179,39 @@ public class activity { response.put("message", "Toilets List."); response.put("data", result); + return Collections.singletonList(response); + } + + @Transactional + public List> toiletlistRest( + MultiValueMap formData, + String latitude, + String longitude) { + + String sqlWhere = ""; + + if (latitude != null && longitude != null && !latitude.isBlank() && !latitude.isEmpty() && !longitude.isBlank() + && !longitude.isEmpty()) { + sqlWhere += " AND ((6371008.8 * acos(ROUND(cos(radians(" + latitude + + ")) * cos(radians(latitude)) * cos(radians(longitude) - radians(" + longitude + + ")) + sin(radians(" + latitude + ")) * sin(radians(latitude)), 9))) < 200)" + + " ORDER BY `id` DESC"; + } + + String sqlQuery = "SELECT *," + + " CONCAT('"+fileBaseUrl+"/gccofficialapp/files',image) AS photo " + + " FROM `gcc_toilet_list` WHERE `isactive`=1" // This is the starting part of WHERE clause + + sqlWhere; // Here the latitude and longitude condition gets appended if provided + + List> result = jdbcToiletsTemplate.queryForList(sqlQuery); + Map response = new HashMap<>(); + response.put("status", 200); + response.put("message", "Nearby toilet list."); + if(result.isEmpty()) { + response.put("message", "No toilet found nearby."); + } + response.put("data", result); + return Collections.singletonList(response); } diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/viewCutter/controller/viewCutterController.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/viewCutter/controller/viewCutterController.java new file mode 100644 index 0000000..3ea38a9 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/viewCutter/controller/viewCutterController.java @@ -0,0 +1,135 @@ +package in.gov.chennaicorporation.mobileservice.viewCutter.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.MultiValueMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import in.gov.chennaicorporation.mobileservice.viewCutter.service.viewCutterActivity; + + +@RequestMapping("/gccofficialapp/api/viewcutter/") +@RestController("viewCutterRest") +public class viewCutterController { + @Autowired + private viewCutterActivity viewCutterActivity; + + @PostMapping(value="/saveViewCutterData") + public List saveViewCutterData( + @RequestParam(value="loginId", required = true) String cby, + @RequestParam(value="latitude", required = true) String latitude, + @RequestParam(value="longitude", required = true) String longitude, + @RequestParam(value="zone", required = true) String zone, + @RequestParam(value="ward", required = true) String ward, + @RequestParam(value="streetname", required = false) String streetname, + @RequestParam(value="streetid", required = false) String streetid, + @RequestParam(value="remarks", required = true) String remarks, + + @RequestParam(value="file", required = false) MultipartFile file + ){ + return viewCutterActivity.saveViewCutterData(cby, zone, ward, streetid, streetname, latitude, longitude, remarks, file); + } + + @GetMapping(value="/getViewCutterList") + public List getViewCutterList(@RequestParam MultiValueMap formData, + @RequestParam(value = "latitude", required = true) String latitude, + @RequestParam(value = "longitude", required = true) String longitude, + @RequestParam(value = "loginid", required = false) String loginid){ + return viewCutterActivity.getViewCutterList(formData, latitude, longitude, loginid); + } + + @GetMapping(value="/getViewCutterCompletedList") + public List getViewCutterCompletedList(@RequestParam MultiValueMap formData, + @RequestParam(value = "latitude", required = false) String latitude, + @RequestParam(value = "longitude", required = false) String longitude, + @RequestParam(value = "loginid", required = true) String loginid){ + return viewCutterActivity.getViewCutterCompletedList(formData, latitude, longitude, loginid); + } + + @GetMapping(value="/getStageList") // Old App + public List getQuestionsList(@RequestParam(value="loginId", required = false) String cby){ + return viewCutterActivity.getStageList(); + } + + @GetMapping(value="/getViewCutterDetails") + public List getViewCutterDetails( + @RequestParam MultiValueMap formData, + @RequestParam(value="id", required = true) String id, + @RequestParam(value="latitude", required = true) String latitude, + @RequestParam(value="longitude", required = true) String longitude, + @RequestParam(value="loginid", required = false) String loginid, + @RequestParam(value="streetid", required = true) String streetid, + @RequestParam(value="undertaken_condition", required = false) String undertaken_condition){ + return viewCutterActivity.getViewCutterDetails(formData,id,loginid, latitude, longitude, undertaken_condition, streetid); + } + + @PostMapping(value="/saveStageActivityData") + public List saveStageActivityData( + @RequestParam(value="id", required = true) String id, + @RequestParam(value="loginId", required = true) String cby, + @RequestParam(value="latitude", required = true) String latitude, + @RequestParam(value="longitude", required = true) String longitude, + @RequestParam(value="zone", required = true) String zone, + @RequestParam(value="ward", required = true) String ward, + @RequestParam(value="streetname", required = false) String streetname, + @RequestParam(value="streetid", required = false) String streetid, + @RequestParam(value="stageid", required = true) String stageid, + @RequestParam(value="remarks", required = true) String remarks, + @RequestParam(value="weightage", required = true) String weightage, + @RequestParam(value="undertaken", required = false) String undertaken, + + @RequestParam(value="stagefile", required = false) MultipartFile stage_file + ){ + return viewCutterActivity.saveStageActivityData(id, cby, latitude, longitude, zone, ward, + streetname, streetid, stageid, remarks, weightage, stage_file, undertaken); + } + + // Reports + + @GetMapping(value="/getZoneList") + public List getZoneList(){ + return viewCutterActivity.getZoneList(); + } + + @GetMapping(value="/getWardList") + public List getWardList(@RequestParam(value="zone", required = true) String zone){ + return viewCutterActivity.getWardList(zone); + } + + @GetMapping(value="/getUndertakenList") + public List getUndertakenList(@RequestParam(value="ward", required = true) String ward){ + return viewCutterActivity.getUndertakenList(ward); + } + + @GetMapping(value="/getNotUndertakenList") + public List getNotUndertakenList(@RequestParam(value="ward", required = true) String ward){ + return viewCutterActivity.getNotUndertakenList(ward); + } + + @GetMapping(value="/getWorkPendingList") + public List getWorkPendingList(@RequestParam(value="ward", required = true) String ward){ + return viewCutterActivity.getWorkPendingList(ward); + } + + @GetMapping(value="/getWorkCompletedList") + public List getWorkCompletedList(@RequestParam(value="ward", required = true) String ward){ + return viewCutterActivity.getWorkCompletedList(ward); + } + + @GetMapping(value="/getReportViewCutterDetails") + public List getReportViewCutterDetails( + @RequestParam MultiValueMap formData, + @RequestParam(value="id", required = true) String id, + @RequestParam(value="latitude", required = true) String latitude, + @RequestParam(value="longitude", required = true) String longitude, + @RequestParam(value="loginid", required = false) String loginid, + @RequestParam(value="undertaken_condition", required = false) String undertaken_condition){ + return viewCutterActivity.getReportViewCutterDetails(formData,id,loginid, latitude, longitude, undertaken_condition); + } +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/viewCutter/package-info.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/viewCutter/package-info.java new file mode 100644 index 0000000..4244ba3 --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/viewCutter/package-info.java @@ -0,0 +1 @@ +package in.gov.chennaicorporation.mobileservice.viewCutter; \ No newline at end of file diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/viewCutter/service/viewCutterActivity.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/viewCutter/service/viewCutterActivity.java new file mode 100644 index 0000000..25b162c --- /dev/null +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/viewCutter/service/viewCutterActivity.java @@ -0,0 +1,1037 @@ +package in.gov.chennaicorporation.mobileservice.viewCutter.service; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.SecureRandom; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import javax.imageio.ImageIO; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.stream.ImageOutputStream; +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.core.env.Environment; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.PreparedStatementCreator; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.MultiValueMap; +import org.springframework.web.multipart.MultipartFile; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import in.gov.chennaicorporation.mobileservice.gccactivity.service.DateTimeUtil; + +@Service +public class viewCutterActivity { +private JdbcTemplate jdbcViewCutterTemplate; + + private final Environment environment; + private String fileBaseUrl; + + private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + private static final int STRING_LENGTH = 15; + private static final Random RANDOM = new SecureRandom(); + + @Autowired + public void setDataSource(@Qualifier("mysqlViewCutterDataSource") DataSource ViewCutterDataSource) { + this.jdbcViewCutterTemplate = new JdbcTemplate(ViewCutterDataSource); + } + + @Autowired + public viewCutterActivity(Environment environment) { + this.environment = environment; + this.fileBaseUrl=environment.getProperty("fileBaseUrl"); + } + + public static String generateRandomString() { + StringBuilder result = new StringBuilder(STRING_LENGTH); + for (int i = 0; i < STRING_LENGTH; i++) { + result.append(CHARACTERS.charAt(RANDOM.nextInt(CHARACTERS.length()))); + } + return result.toString(); + } + + public static String generateRandomStringForFile(int String_Lenth) { + StringBuilder result = new StringBuilder(String_Lenth); + for (int i = 0; i < STRING_LENGTH; i++) { + result.append(CHARACTERS.charAt(RANDOM.nextInt(CHARACTERS.length()))); + } + return result.toString(); + } + + private byte[] compressImage(BufferedImage image, float quality) throws IOException { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(byteArrayOutputStream); + + ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next(); + writer.setOutput(imageOutputStream); + + ImageWriteParam param = writer.getDefaultWriteParam(); + if (param.canWriteCompressed()) { + param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); + param.setCompressionQuality(quality); + } + + writer.write(null, new javax.imageio.IIOImage(image, null, null), param); + + writer.dispose(); + imageOutputStream.close(); + + return byteArrayOutputStream.toByteArray(); + } + + public String fileUpload(String name, String id, MultipartFile file) { + + int lastInsertId = 0; + // Set the file path where you want to save it + String uploadDirectory = environment.getProperty("file.upload.directory"); + String serviceFolderName = environment.getProperty("view_cutter_foldername"); + var year =DateTimeUtil.getCurrentYear(); + var month =DateTimeUtil.getCurrentMonth(); + + uploadDirectory = uploadDirectory + serviceFolderName + year +"/"+month; + + try { + // Create directory if it doesn't exist + Path directoryPath = Paths.get(uploadDirectory); + if (!Files.exists(directoryPath)) { + Files.createDirectories(directoryPath); + } + + // Datetime string + String datetimetxt = DateTimeUtil.getCurrentDateTime(); + // File name + System.out.println(file.getOriginalFilename()); + String fileName = name+ "_" +id + "_" + datetimetxt + "_" + generateRandomStringForFile(10) + "_" + file.getOriginalFilename(); + fileName = fileName.replaceAll("\\s+", ""); // Remove space on filename + + String filePath = uploadDirectory + "/" + fileName; + + String filepath_txt = "/"+serviceFolderName + year + "/" + month + "/" + fileName; + + // Create a new Path object + Path path = Paths.get(filePath); + + // Get the bytes of the file + byte[] bytes = file.getBytes(); + + // Compress the image + BufferedImage image = ImageIO.read(new ByteArrayInputStream(bytes)); + byte[] compressedBytes = compressImage(image, 0.5f); // Compress with 50% quality + + // Write the bytes to the file + Files.write(path, bytes); + + System.out.println(filePath); + return filepath_txt; + + } catch (IOException e) { + e.printStackTrace(); + return "Failed to save file " + file.getOriginalFilename(); + } + } + + ////////////////////////////// + public String getConfigValue() { + String sqlQuery = "SELECT `id`, `lat_long_radius` FROM `config` LIMIT 1"; + String value = "50"; // default fallback value + List> results = jdbcViewCutterTemplate.queryForList(sqlQuery); + + if (!results.isEmpty()) { + Map row = results.get(0); + value = String.valueOf(row.get("lat_long_radius")); // corrected key name + } + + return value; + } + ////////////////////////////// + + @Transactional + public List> saveViewCutterData( + String cby, + String zone, + String ward, + String street_id, + String street_name, + String latitudeStr, + String longitudeStr, + String remarks, + MultipartFile file) { + List> result = null; + Map response = new HashMap<>(); + + /////// Check ////// + double latitude = Double.parseDouble(latitudeStr); + double longitude = Double.parseDouble(longitudeStr); + + String checkSql = "SELECT count(*) FROM view_cutter_list " + + "WHERE street_id = ? " + + "AND isactive = 1 AND isdelete = 0 " + + "AND (6371008.8 * ACOS(" + + "COS(RADIANS(?)) * COS(RADIANS(latitude)) * " + + "COS(RADIANS(longitude) - RADIANS(?)) + " + + "SIN(RADIANS(?)) * SIN(RADIANS(latitude))" + + ")) < ?"; + + Integer count = jdbcViewCutterTemplate.queryForObject(checkSql, Integer.class, street_id, latitude, longitude, latitude, getConfigValue()); + + if (count != null && count > 0) { + response.put("status", "error"); + response.put("message", "duplicate"); + return Collections.singletonList(response); + } + //////// + + int lastInsertId = 0; + + String image = ""; + + var year = DateTimeUtil.getCurrentYear(); + var month = DateTimeUtil.getCurrentMonth(); + + // Handle file upload if a file is provided + if (file != null && !file.isEmpty()) { + image = fileUpload(zone+"_"+ward, street_id, file); + } + + String baseimg = image; + + // Get today's date + LocalDate today = LocalDate.now(); + + // Format it in the desired format (yyyy-MM-dd) + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + String todayDate = today.format(formatter); + + String sqlQuery = "INSERT INTO `view_cutter_list`(" + + "`zone`, `ward`, `street_id`, `street_name`, `latitude`, `longitude`, `image`, `remarks`, `cby`" + + ") " + + "VALUES (?,?,?,?,?,?,?,?,?)"; + + KeyHolder keyHolder = new GeneratedKeyHolder(); + + try { + int affectedRows = jdbcViewCutterTemplate.update(new PreparedStatementCreator() { + @Override + public PreparedStatement createPreparedStatement(Connection connection) throws SQLException { + PreparedStatement ps = connection.prepareStatement(sqlQuery, new String[] { "vcid" }); + int i =1; + ps.setString(i++, zone); + ps.setString(i++, ward); + ps.setString(i++, street_id); + ps.setString(i++, street_name); + ps.setString(i++, latitudeStr); + ps.setString(i++, longitudeStr); + ps.setString(i++, baseimg); + ps.setString(i++, remarks); + ps.setString(i++, cby); + + return ps; + } + }, keyHolder); + + if (affectedRows > 0) { + Number generatedId = keyHolder.getKey(); + lastInsertId = (generatedId != null) ? generatedId.intValue() : 0; + response.put("insertId", lastInsertId); + response.put("status", "success"); + response.put("message", "A View Cutter data was inserted successfully!"); + System.out.println("A View Cutter data was inserted successfully! View Cutter ID: " + generatedId); + + } else { + response.put("status", "error"); + response.put("message", "Failed to insert New View Cutter details."); + } + + } catch (DataAccessException e) { + System.out.println("Data Access Exception:"); + Throwable rootCause = e.getMostSpecificCause(); + if (rootCause instanceof SQLException) { + SQLException sqlException = (SQLException) rootCause; + System.out.println(today + ": View Cutter SQL State: " + sqlException.getSQLState()); + System.out.println("View Cutter Error Code: " + sqlException.getErrorCode()); + System.out.println("View Cutter Message: " + sqlException.getMessage()); + response.put("status", "error"); + response.put("message", sqlException.getMessage()); + response.put("sqlState", sqlException.getSQLState()); + response.put("errorCode", sqlException.getErrorCode()); + } else { + System.out.println("Message: " + rootCause.getMessage()); + response.put("status", "error"); + response.put("message", rootCause.getMessage()); + } + } + + return Collections.singletonList(response); + } + + public List> getViewCutterList( + MultiValueMap formData, + String latitude, + String longitude, + String loginid + ) { + + String sqlWhere = ""; + + String radius = getConfigValue(); + + if (latitude != null && longitude != null && !latitude.isBlank() && !latitude.isEmpty() && !longitude.isBlank() + && !longitude.isEmpty()) { + sqlWhere += " AND ((6371008.8 * acos((cos(radians(" + latitude + + ")) * cos(radians(vcl.latitude)) * cos(radians(vcl.longitude) - radians(" + longitude + + ")) + sin(radians(" + latitude + ")) * sin(radians(vcl.latitude))))) < "+radius+")"; + } + + sqlWhere = " AND (vcu.`stage_status` <> 'Completed' OR vcu.`stage_status` is NULL) ORDER BY vcl.`vcid` DESC"; + + String sql = "SELECT " + + " vcl.`vcid`, " + + " vcl.`zone`, " + + " vcl.`ward`, " + + " vcl.`latitude`, " + + " vcl.`longitude`, " + + " vcl.`street_id`, " + + " vcl.`street_name`, " + + " vcu.undertaken, " + + " IF(vcl.image IS NOT NULL AND vcl.image != '', " + + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files', vcl.image), " + + " NULL) AS image, " + + " COALESCE(vcu.stage_status,'Pending') AS stage_status " + + "FROM `view_cutter_list` vcl " + + "LEFT JOIN `view_cutter_undertaken` vcu " + + " ON vcu.vcid = vcl.vcid AND vcu.isactive = 1 " + + "WHERE vcl.isactive = 1 "+sqlWhere; + + //System.out.println(sql); + + List> result = jdbcViewCutterTemplate.queryForList(sql); + + ObjectMapper mapper = new ObjectMapper(); + for (Map row : result) { + + Object undertaken = row.get("undertaken"); + + if (undertaken != null) { + sql = "SELECT COALESCE(SUM(`weightage`), 0) AS total_weightage " + + "FROM `view_cutter_undertaken_data` " + + "WHERE vcid = ?"; + + List> presentage = jdbcViewCutterTemplate.queryForList(sql, row.get("vcid")); + + // Safely get the first result + if (!presentage.isEmpty()) { + row.put("stage_presentage", presentage.get(0).get("total_weightage")); + } else { + row.put("stage_presentage", 0); + } + } else { + row.put("stage_presentage", 0); + } + + } + + + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "View Cutter List."); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> getViewCutterCompletedList( + MultiValueMap formData, + String latitude, + String longitude, + String loginid + ) { + + String sqlWhere = ""; + String radius = getConfigValue(); + /* + if (latitude != null && longitude != null && !latitude.isBlank() && !latitude.isEmpty() && !longitude.isBlank() + && !longitude.isEmpty()) { + sqlWhere += " AND ((6371008.8 * acos((cos(radians(" + latitude + + ")) * cos(radians(vcl.latitude)) * cos(radians(vcl.longitude) - radians(" + longitude + + ")) + sin(radians(" + latitude + ")) * sin(radians(vcl.latitude))))) < "+radius+")" + + " ORDER BY" + + " vcl.`vcid` DESC"; + } + */ + String sql = "SELECT " + + " vcl.`vcid`, " + + " vcl.`zone`, " + + " vcl.`ward`, " + + " vcl.`latitude`, " + + " vcl.`longitude`, " + + " vcl.`street_id`, " + + " vcl.`street_name`, " + + " vcu.undertaken, " + + " IF(vcl.image IS NOT NULL AND vcl.image != '', " + + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files', vcl.image), " + + " NULL) AS image, " + + " COALESCE(vcu.stage_status,'Pending') AS stage_status " + + "FROM `view_cutter_list` vcl " + + "LEFT JOIN `view_cutter_undertaken` vcu " + + " ON vcu.vcid = vcl.vcid AND vcu.isactive = 1 " + + "WHERE vcl.isactive = 1 AND vcu.stage_status='Completed'"; // +sqlWhere; + + System.out.println(sql); + + List> result = jdbcViewCutterTemplate.queryForList(sql); + + ObjectMapper mapper = new ObjectMapper(); + for (Map row : result) { + + Object undertaken = row.get("undertaken"); + + if (undertaken != null) { + sql = "SELECT COALESCE(SUM(`weightage`), 0) AS total_weightage " + + "FROM `view_cutter_undertaken_data` " + + "WHERE vcid = ?"; + + List> presentage = jdbcViewCutterTemplate.queryForList(sql, row.get("vcid")); + + // Safely get the first result + if (!presentage.isEmpty()) { + row.put("stage_presentage", presentage.get(0).get("total_weightage")); + } else { + row.put("stage_presentage", 0); + } + } else { + row.put("stage_presentage", 0); + } + + } + + + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "View Cutter Completed List."); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> getStageList() { + String sql = "SELECT * FROM `renovation_statge` WHERE isactive=1 ORDER BY orderby"; + List> result = jdbcViewCutterTemplate.queryForList(sql); + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "View Cutter Stages."); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> getViewCutterDetails( + MultiValueMap formData, + String vcid, + String loginid, + String latitude, + String longitude, + String undertaken_condition, + String street_id + ) { + + String sqlWhere = ""; + //String radius = getConfigValue(); + + String sql = "SELECT " + + " vcl.`vcid`, " + + " vcl.`zone`, " + + " vcl.`ward`, " + + " vcl.`latitude`, " + + " vcl.`longitude`, " + + " vcl.`street_id`, " + + " vcl.`street_name`, " + + " vcu.undertaken, " + + " IF(vcl.image IS NOT NULL AND vcl.image != '', " + + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files', vcl.image), " + + " NULL) AS image, " + + " COALESCE(vcu.stage_status,'Pending') AS stage_status " + + "FROM `view_cutter_list` vcl " + + "LEFT JOIN `view_cutter_undertaken` vcu " + + " ON vcu.vcid = vcl.vcid AND vcu.isactive = 1 " + + "WHERE vcl.vcid = ? AND vcl.`street_id` = ? "; + + System.out.println(sql); + + List> result = jdbcViewCutterTemplate.queryForList(sql, vcid, street_id); + + ObjectMapper mapper = new ObjectMapper(); + for (Map row : result) { + + Object undertaken = row.get("undertaken"); + + if (undertaken != null) { + sql = "SELECT COALESCE(SUM(`weightage`), 0) AS total_weightage " + + "FROM `view_cutter_undertaken_data` " + + "WHERE vcid = ?"; + + List> presentage = jdbcViewCutterTemplate.queryForList(sql, row.get("vcid")); + + // Safely get the first result + if (!presentage.isEmpty()) { + row.put("stage_presentage", presentage.get(0).get("total_weightage")); + } else { + row.put("stage_presentage", 0); + } + } else { + row.put("stage_presentage", 0); + } + + // Location Check + double shelterLat = Double.parseDouble(row.get("latitude").toString()); + double shelterLng = Double.parseDouble(row.get("longitude").toString()); + double userLat = Double.parseDouble(latitude); + double userLng = Double.parseDouble(longitude); + + // Calculate distance using Haversine formula + double earthRadius = 6371008.8; // in meters + double dLat = Math.toRadians(userLat - shelterLat); + double dLng = Math.toRadians(userLng - shelterLng); + double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + + Math.cos(Math.toRadians(shelterLat)) * Math.cos(Math.toRadians(userLat)) + * Math.sin(dLng / 2) * Math.sin(dLng / 2); + double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + double distance = earthRadius * c; + + double radiusInMeters = Double.parseDouble(getConfigValue()); + row.put("user_on_correct_location", distance <= radiusInMeters); // true if within radius meters + //////// + + if(!"0".equals(undertaken_condition)) { + + // Stages + List> stageListRaw = getStageList(); + List> stageList = (List>) stageListRaw.get(0).get("data"); + List> stagedata = new ArrayList<>(); + + for (Map stage : stageList) { + Map stageEntry = new HashMap<>(stage); // Clone base stage info + + stageEntry.put("stageid", stage.get("sid")); + stageEntry.put("stage_name", stage.get("name")); + stageEntry.put("weightage", stage.get("weightage")); + stageEntry.put("orderby", stage.get("orderby")); + + sql = "SELECT `dataid`, `vcid`, `stageid`, " + + "CONCAT('"+fileBaseUrl+"/gccofficialapp/files', `image`) AS `image`, " + + "`remarks`, `weightage`, " + + "`zone`, `ward`, `latitude`, `longitude`, `streetname`, `streetid`, " + + " DATE_FORMAT(`cdate`, '%d-%m-%Y') AS `cdate`, " + + "`cby`, `isactive` FROM `view_cutter_undertaken_data` " + + "WHERE `vcid` = ? AND `stageid` = ? AND isactive = 1"; + + List> resultStageData = jdbcViewCutterTemplate.queryForList(sql, row.get("vcid"), stage.get("sid")); + + if (!resultStageData.isEmpty()) { + Map stageDataRow = resultStageData.get(0); + stageEntry.put("stage_image", stageDataRow.get("image")); + stageEntry.put("stage_remarks", stageDataRow.get("remarks")); + stageEntry.put("stage_date", stageDataRow.get("cdate")); + stageEntry.put("stage_status", "Completed"); + stageEntry.put("stage_presentage", stageDataRow.get("weightage")); + } else { + // Defaults if no data available + stageEntry.put("stage_image", null); + stageEntry.put("stage_remarks", null); + stageEntry.put("stage_date", null); + stageEntry.put("stage_status", "Pending"); + stageEntry.put("stage_presentage", 0); + } + + stagedata.add(stageEntry); + } + row.put("stages", stagedata); + } + + } + + + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "View Cutter With Stage Details."); + response.put("data", result); + + return Collections.singletonList(response); + } + + @Transactional + public String addRenovationBaseData( + String vcid, String undertaken, + String latitude, String longitude, String zone, String ward, + String streetname, String streetid, String stage_status + ) { + String sql ="INSERT INTO `view_cutter_undertaken`(" + + "`vcid`, `undertaken`, " + + "`latitude`, `longitude`, `zone`, `ward`, `streetname`, `streetid`, " + + "`stage_status`) " + + "VALUES (?,?,?,?,?,?,?,?,?)"; + + jdbcViewCutterTemplate.update(sql, vcid, undertaken, latitude, longitude , zone, ward, streetname, streetid, stage_status); + return "success"; + } + + public String updateStageStatus(String vcid, String stage_status, String datetxt) { + + String sql = "UPDATE `view_cutter_undertaken` SET `stage_status`=?,`lastcdate` =? WHERE `vcid`=?"; + jdbcViewCutterTemplate.update(sql,stage_status, datetxt, vcid); + + return "sussess"; + } + + @Transactional + public List> saveStageActivityData( + String vcid, + String cby, + String latitude, + String longitude, + String zone, + String ward, + String streetname, + String streetid, + String stageid, + String remarks, + String weightage, + MultipartFile stage_file, + String undertaken) { + List> result = null; + Map response = new HashMap<>(); + int lastInsertId = 0; + + String stage_image = ""; + + var year = DateTimeUtil.getCurrentYear(); + var month = DateTimeUtil.getCurrentMonth(); + + // Stage Images + if (stage_file != null && !stage_file.isEmpty()) { + stage_image = fileUpload("stage", stageid, stage_file); + } + + String stage_image_txt = stage_image; + + //String type = // Get before & after + + // Get today's date + LocalDate today = LocalDate.now(); + + // Format it in the desired format (yyyy-MM-dd) + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + String todayDate = today.format(formatter); + + String stage_status = "Pending"; + + if("0".equals(undertaken) || "1".equals(undertaken)) { + + addRenovationBaseData(vcid, undertaken, latitude, longitude , zone, ward, streetname, streetid, stage_status); + } + if("0".equals(undertaken)) { + stage_status = "Completed"; + updateStageStatus(vcid, stage_status, todayDate); + } + if(!"0".equals(undertaken)) { + String sqlQuery = "INSERT INTO `view_cutter_undertaken_data`(" + + "`vcid`, `stageid`, `image`, `remarks`, `weightage`, `zone`, " + + "`ward`, `latitude`, `longitude`, `streetname`, `streetid`, `cby`" + + ") " + + "VALUES (?,?,?,?,?,?,?,?,?,?,?,?)"; + + KeyHolder keyHolder = new GeneratedKeyHolder(); + + try { + int affectedRows = jdbcViewCutterTemplate.update(new PreparedStatementCreator() { + @Override + public PreparedStatement createPreparedStatement(Connection connection) throws SQLException { + PreparedStatement ps = connection.prepareStatement(sqlQuery, new String[] { "dataid" }); + ps.setString(1, vcid); + ps.setString(2, stageid); + ps.setString(3, stage_image_txt); + ps.setString(4, remarks); + ps.setString(5, weightage); + ps.setString(6, zone); + ps.setString(7, ward); + ps.setString(8, latitude); + ps.setString(9, longitude); + ps.setString(10, streetname); + ps.setString(11, streetid); + ps.setString(12, cby); + + return ps; + } + }, keyHolder); + + if (affectedRows > 0) { + Number generatedId = keyHolder.getKey(); + lastInsertId = (generatedId != null) ? generatedId.intValue() : 0; + response.put("insertId", lastInsertId); + response.put("status", "success"); + response.put("message", "A View Cutter stage data was inserted successfully!"); + System.out.println("A View Cutter stage data was inserted successfully! View Cutter ID: " + generatedId); + + String sql = "SELECT COALESCE(SUM(`weightage`), 0) AS total_weightage " + + "FROM `view_cutter_undertaken_data` " + + "WHERE vcid = ?"; + List> resultStageData = jdbcViewCutterTemplate.queryForList(sql, vcid ); + + Object totalWeightageObj = resultStageData.get(0).get("total_weightage"); + double totalWeightage = totalWeightageObj != null ? Double.parseDouble(totalWeightageObj.toString()) : 0; + + if (totalWeightage >= 100) { + stage_status = "Completed"; + } + + updateStageStatus(vcid, stage_status, todayDate); + + } else { + response.put("status", "error"); + response.put("message", "Failed to insert a View Cutter stage data. View Cutter ID:" + vcid); + } + + } catch (DataAccessException e) { + System.out.println("Data Access Exception:"); + Throwable rootCause = e.getMostSpecificCause(); + if (rootCause instanceof SQLException) { + SQLException sqlException = (SQLException) rootCause; + System.out.println("SQL State: " + sqlException.getSQLState()); + System.out.println("Error Code: " + sqlException.getErrorCode()); + System.out.println("Message: " + sqlException.getMessage()); + response.put("status", "error"); + response.put("message", sqlException.getMessage()); + response.put("sqlState", sqlException.getSQLState()); + response.put("errorCode", sqlException.getErrorCode()); + } else { + System.out.println("Message: " + rootCause.getMessage()); + response.put("status", "error"); + response.put("message", rootCause.getMessage()); + } + } + } + else { + response.put("insertId", 0); + response.put("status", "success"); + response.put("message", "0 - A View Cutter stage data was inserted successfully!"); + } + return Collections.singletonList(response); + } + +// Reports + + public List> getZoneList() { + String sql = "SELECT " + + " vcl.zone, " + + " COUNT(DISTINCT vcl.vcid) AS total_view, " + + " COUNT(DISTINCT CASE WHEN vcu.undertaken = 1 THEN vcu.vcid END) AS total_need_improvement, " + + " COUNT(DISTINCT CASE WHEN vcu.undertaken = 0 THEN vcu.vcid END) AS total_no_improvement, " + + " COUNT(DISTINCT CASE WHEN vcu.stage_status != 'Completed' AND vcu.stage_status IS NOT NULL THEN vcu.vcid END) AS total_pending, " + + " COUNT(DISTINCT CASE WHEN vcu.stage_status = 'Completed' THEN vcu.vcid END) AS total_completed " + + "FROM " + + " view_cutter_list vcl " + + "LEFT JOIN " + + " view_cutter_undertaken vcu ON vcu.vcid = vcl.vcid AND vcu.isactive = 1 " + + "WHERE " + + " vcl.isactive = 1 " + + "GROUP BY " + + " vcl.zone " + + "ORDER BY " + + " vcl.zone"; + List> result = jdbcViewCutterTemplate.queryForList(sql); + // Compute totals + Map totals = new HashMap<>(); + totals.put("zone", "Total"); + + String[] keys = { + "total_view", + "total_need_improvement", "total_no_improvement", + "total_pending", "total_completed" + }; + + for (String key : keys) { + int sum = result.stream() + .mapToInt(row -> row.get(key) != null ? ((Number) row.get(key)).intValue() : 0) + .sum(); + totals.put(key, sum); + } + // Add totals row at the end + result.add(totals); + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "View Cutter Zone Report."); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> getWardList(String zone) { + String sql = "SELECT " + + " vcl.ward," + + " COUNT(DISTINCT vcl.vcid) AS total_view," + + " COUNT(DISTINCT CASE WHEN vcu.undertaken = 1 THEN vcu.vcid END) AS total_need_improvement," + + " COUNT(DISTINCT CASE WHEN vcu.undertaken = 0 THEN vcu.vcid END) AS total_no_improvement," + + " COUNT(DISTINCT CASE WHEN vcu.stage_status != 'Completed' AND vcu.stage_status IS NOT NULL THEN vcu.vcid END) AS total_pending," + + " COUNT(DISTINCT CASE WHEN vcu.stage_status = 'Completed' THEN vcu.vcid END) AS total_completed " + + "FROM " + + " view_cutter_list vcl " + + "LEFT JOIN " + + " view_cutter_undertaken vcu ON vcu.vcid = vcl.vcid AND vcu.isactive = 1 " + + "WHERE " + + " vcl.isactive = 1 " + + " AND vcl.zone = ? " + + "GROUP BY " + + " vcl.ward " + + "ORDER BY " + + " vcl.ward"; + List> result = jdbcViewCutterTemplate.queryForList(sql,zone); + // Compute totals + Map totals = new HashMap<>(); + totals.put("ward", "Total"); + + String[] keys = { + "total_view", + "total_need_improvement", "total_no_improvement", + "total_pending", "total_completed" + }; + + for (String key : keys) { + int sum = result.stream() + .mapToInt(row -> row.get(key) != null ? ((Number) row.get(key)).intValue() : 0) + .sum(); + totals.put(key, sum); + } + + // Add totals row at the end + result.add(totals); + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "View Cutter Ward Report."); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> getUndertakenList(String ward) { + String sql = "SELECT vcl.vcid, vcl.zone, vcl.ward, vcl.street_name, vcl.latitude, vcl.longitude, vcu.stage_status " + + "FROM view_cutter_list vcl " + + "LEFT JOIN view_cutter_undertaken vcu ON vcu.vcid = vcl.vcid AND vcu.isactive = 1 " + + "WHERE vcl.isactive = 1 " + + "AND vcl.ward = ? AND vcu.undertaken=1"; + + List> result = jdbcViewCutterTemplate.queryForList(sql, ward); + + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "View Cutter Undertaken is `Yes` in ward " + ward); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> getNotUndertakenList(String ward) { + String sql = "SELECT vcl.vcid, vcl.zone, vcl.ward, vcl.street_name, vcl.latitude, vcl.longitude, vcu.stage_status " + + "FROM view_cutter_list vcl " + + "LEFT JOIN view_cutter_undertaken vcu ON vcu.vcid = vcl.vcid AND vcu.isactive = 1 " + + "WHERE vcl.isactive = 1 " + + "AND vcl.ward = ? AND vcu.undertaken=0"; + + List> result = jdbcViewCutterTemplate.queryForList(sql, ward); + + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "View Cutter Undertaken is `No` in ward " + ward); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> getWorkPendingList(String ward) { + String sql = "SELECT vcl.vcid, vcl.zone, vcl.ward, vcl.street_name, vcl.latitude, vcl.longitude, vcu.stage_status " + + "FROM view_cutter_list vcl " + + "INNER JOIN view_cutter_undertaken vcu ON vcu.vcid = vcl.vcid AND vcu.isactive = 1 " + + "WHERE vcl.isactive = 1 " + + "AND vcl.ward = ? AND COALESCE(vcu.stage_status, 'Pending') != 'Completed'"; + + List> result = jdbcViewCutterTemplate.queryForList(sql, ward); + + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "View Cutter work pending list for ward " + ward); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> getWorkCompletedList(String ward) { + String sql = "SELECT vcl.vcid, vcl.zone, vcl.ward, vcl.street_name, vcl.latitude, vcl.longitude, vcu.stage_status " + + "FROM view_cutter_list vcl " + + "INNER JOIN view_cutter_undertaken vcu ON vcu.vcid = vcl.vcid AND vcu.isactive = 1 " + + "WHERE vcl.isactive = 1 " + + "AND vcl.ward = ? AND COALESCE(vcu.stage_status, 'Pending') = 'Completed'"; + + List> result = jdbcViewCutterTemplate.queryForList(sql, ward); + + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "View Cutter work pending list for ward " + ward); + response.put("data", result); + + return Collections.singletonList(response); + } + + public List> getReportViewCutterDetails( + MultiValueMap formData, + String vcid, + String loginid, + String latitude, + String longitude, + String undertaken_condition + ) { + + String sqlWhere = ""; + //String radius = getConfigValue(); + + String sql = "SELECT " + + " vcl.`vcid`, " + + " vcl.`zone`, " + + " vcl.`ward`, " + + " vcl.`latitude`, " + + " vcl.`longitude`, " + + " vcl.`street_id`, " + + " vcl.`street_name`, " + + " vcu.undertaken, " + + " IF(vcl.image IS NOT NULL AND vcl.image != '', " + + " CONCAT('" + fileBaseUrl + "/gccofficialapp/files', vcl.image), " + + " NULL) AS image, " + + " COALESCE(vcu.stage_status,'Pending') AS stage_status " + + "FROM `view_cutter_list` vcl " + + "LEFT JOIN `view_cutter_undertaken` vcu " + + " ON vcu.vcid = vcl.vcid AND vcu.isactive = 1 " + + "WHERE vcl.vcid = ? "; + + + List> result = jdbcViewCutterTemplate.queryForList(sql, vcid); + + ObjectMapper mapper = new ObjectMapper(); + for (Map row : result) { + + Object undertaken = row.get("undertaken"); + + if (undertaken != null) { + sql = "SELECT COALESCE(SUM(`weightage`), 0) AS total_weightage " + + "FROM `view_cutter_undertaken_data` " + + "WHERE vcid = ?"; + + List> presentage = jdbcViewCutterTemplate.queryForList(sql, row.get("vcid")); + + // Safely get the first result + if (!presentage.isEmpty()) { + row.put("stage_presentage", presentage.get(0).get("total_weightage")); + } else { + row.put("stage_presentage", 0); + } + } else { + row.put("stage_presentage", 0); + } + + // Location Check + double shelterLat = Double.parseDouble(row.get("latitude").toString()); + double shelterLng = Double.parseDouble(row.get("longitude").toString()); + double userLat = Double.parseDouble(latitude); + double userLng = Double.parseDouble(longitude); + + // Calculate distance using Haversine formula + double earthRadius = 6371008.8; // in meters + double dLat = Math.toRadians(userLat - shelterLat); + double dLng = Math.toRadians(userLng - shelterLng); + double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + + Math.cos(Math.toRadians(shelterLat)) * Math.cos(Math.toRadians(userLat)) + * Math.sin(dLng / 2) * Math.sin(dLng / 2); + double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + double distance = earthRadius * c; + + double radiusInMeters = Double.parseDouble(getConfigValue()); + row.put("user_on_correct_location", distance <= radiusInMeters); // true if within radius meters + //////// + + if(Boolean.TRUE.equals(undertaken)) { + + // Stages + List> stageListRaw = getStageList(); + List> stageList = (List>) stageListRaw.get(0).get("data"); + List> stagedata = new ArrayList<>(); + + for (Map stage : stageList) { + Map stageEntry = new HashMap<>(stage); // Clone base stage info + + stageEntry.put("stageid", stage.get("sid")); + stageEntry.put("stage_name", stage.get("name")); + stageEntry.put("weightage", stage.get("weightage")); + stageEntry.put("orderby", stage.get("orderby")); + + sql = "SELECT `dataid`, `vcid`, `stageid`, " + + "CONCAT('"+fileBaseUrl+"/gccofficialapp/files', `image`) AS `image`, " + + "`remarks`, `weightage`, " + + "`zone`, `ward`, `latitude`, `longitude`, `streetname`, `streetid`, " + + " DATE_FORMAT(`cdate`, '%d-%m-%Y') AS `cdate`, " + + "`cby`, `isactive` FROM `view_cutter_undertaken_data` " + + "WHERE `vcid` = ? AND `stageid` = ? AND isactive = 1"; + + List> resultStageData = jdbcViewCutterTemplate.queryForList(sql, row.get("vcid"), stage.get("sid")); + + if (!resultStageData.isEmpty()) { + Map stageDataRow = resultStageData.get(0); + stageEntry.put("stage_image", stageDataRow.get("image")); + stageEntry.put("stage_remarks", stageDataRow.get("remarks")); + stageEntry.put("stage_date", stageDataRow.get("cdate")); + stageEntry.put("stage_status", "Completed"); + stageEntry.put("stage_presentage", stageDataRow.get("weightage")); + } else { + // Defaults if no data available + stageEntry.put("stage_image", null); + stageEntry.put("stage_remarks", null); + stageEntry.put("stage_date", null); + stageEntry.put("stage_status", "Pending"); + stageEntry.put("stage_presentage", 0); + } + + stagedata.add(stageEntry); + } + row.put("stages", stagedata); + } + + } + + + Map response = new HashMap<>(); + response.put("status", "Success"); + response.put("message", "View Cutter With Stage Details."); + response.put("data", result); + + return Collections.singletonList(response); + } + +} diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/works/controller/WorksController.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/works/controller/WorksController.java index 1eaa5f0..af83d16 100644 --- a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/works/controller/WorksController.java +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/works/controller/WorksController.java @@ -68,7 +68,7 @@ public class WorksController { @RequestParam(value = "latitude", required = true) String latitude, @RequestParam(value = "longitude", required = true) String longitude ) { - return worksService.addTaskStageActivityData(estid, tmid, wtid, activityfile, percentage, remarks, cby, zone, ward, latitude, longitude,"open"); + return worksService.addTaskStageActivityData(estid, tmid, wtid, activityfile, percentage, remarks, cby, zone, ward, latitude, longitude, "open"); } @GetMapping("/getZoneReport") diff --git a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/works/service/WorksService.java b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/works/service/WorksService.java index d31e137..090fa84 100644 --- a/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/works/service/WorksService.java +++ b/mobileservice/src/main/java/in/gov/chennaicorporation/mobileservice/works/service/WorksService.java @@ -518,7 +518,7 @@ public class WorksService { + "JOIN " + " erp_works_stages ews ON ews.estid = ew.estid " + "LEFT JOIN ( " - + " -- Subquery to get only latest entry per estid/wtid/tmid based on highest tdid " + //+ " -- Subquery to get only latest entry per estid/wtid/tmid based on highest tdid " + " SELECT etd.* " + " FROM erp_task_data etd " + " INNER JOIN ( " @@ -554,8 +554,8 @@ public class WorksService { // System.out.println("UPDATE `erp_works_task` SET `percentage`="+percentage+" WHERE `estid`="+estid+" AND `id`="+wtid); // System.out.println("UPDATE `erp_works_task` Status: " + statusAffected); - int rowsAffected = 0; - if (statusAffected > 0) { + //int rowsAffected = 0; + //if (statusAffected > 0) { /* sqlQuery = "UPDATE `works_update` SET `percentage`=? WHERE `id`=?"; rowsAffected = jdbcWorksTemplate.update(sqlQuery, new Object[]{percentage,estid}); @@ -563,8 +563,8 @@ public class WorksService { System.out.println("UPDATE `works_update` SET `percentage`="+percentage+" WHERE `id`="+estid); System.out.println("UPDATE `works_update` Status: " + rowsAffected); */ - } - return rowsAffected > 0; + //} + return true; } diff --git a/mobileservice/src/main/resources/.DS_Store b/mobileservice/src/main/resources/.DS_Store index 16dfc65..c8f6dfd 100644 Binary files a/mobileservice/src/main/resources/.DS_Store and b/mobileservice/src/main/resources/.DS_Store differ diff --git a/mobileservice/src/main/resources/application.properties b/mobileservice/src/main/resources/application.properties index 4456708..71e4be7 100644 --- a/mobileservice/src/main/resources/application.properties +++ b/mobileservice/src/main/resources/application.properties @@ -48,3 +48,12 @@ works_task_foldername = works_activity/ street_vendor_foldername=street_vendor_files/ gcceducation_foldername=education_schools_files/ busshelter_foldername=bus_shelter_files/ +domestic_waste_foldername=domestic_waste_images/ +private_toilets_foldername=private_toilets_activity/ +pothole_foldername=pothole_images/ +roadcut_foldername=roadcut_activity/ +construction_guidelines_foldername=construction_guidelines_images/ +speedbrake_foldername=speedbrake_images/ +busshelter_renovation_foldername=bus_shelter_renovation_files/ +view_cutter_foldername = view_cutter_files/ +buildingdemolition_foldername = building_demolition_files/ diff --git a/mobileservice/src/main/resources/templates/pdf-template.html b/mobileservice/src/main/resources/templates/pdf-template.html new file mode 100644 index 0000000..3ed6555 --- /dev/null +++ b/mobileservice/src/main/resources/templates/pdf-template.html @@ -0,0 +1,108 @@ + + + + + + + + + +
+ GCC Logo +
Greater Chennai Corporation
+
Chennai
+
+ + +
NOTICE
+
UNDER CLEAN AND SAFE CONSTRUCTION GUIDELINES 2025
+ + +
+ Date: dd/mm/yyyy +
+ + +

+ Be under the notice that during a recent inspection conducted by the engineers, Greater Chennai Corporation (GCC), + your construction site located at was found to be in + violation of the "Clean and Safe Construction Guidelines 2025". +

+ +

The following violation(s) have been observed at your site:

+
    +
  • +
+ +

+ These lapses fall under the category of + Significance Violations as per GCC norms. + As per Clause () of the guidelines, you are hereby directed to: +

+ +
    +
  1. Rectify the violations within 15 days from the date of receipt of this notice.
  2. +
  3. Submit photographic/video evidence and compliance report to this office upon rectification.
  4. +
+ +

Failure to comply within 15 days from the date of receipt of this notice shall attract:

+
    +
  1. + Penalty of Rs + () +
  2. +
  3. + Failing to comply within 7 Days of imposing of fine may result in a + “Stop Work Notice” and construction activity at your site will be halted. +
  4. +
+ + + + + +