Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1820,6 +1820,7 @@ public String UserRoleMappings(@RequestBody String userRoleMapping, HttpServletR
resDataMap1.setFacilityID(previl.getFacilityID());
resDataMap1.setNikshayTUID(previl.getNikshayTUID());
resDataMap1.setNikshayFacilityID(previl.getNikshayFacilityID());
resDataMap1.setVanID(previl.getVanID());
resList1.add(resDataMap1);
}

Expand Down Expand Up @@ -1895,6 +1896,7 @@ public String updateUserRoleMapping(@RequestBody String updateUserRoleMapping, H
usrRole.setFacilityID(pre.getFacilityID());
usrRole.setNikshayTUID(pre.getNikshayTUID());
usrRole.setNikshayFacilityID(pre.getNikshayFacilityID());
usrRole.setVanID(pre.getVanID());

if (pre.getTeleConsultation() != null) {
usrRole.setTeleConsultation(pre.getTeleConsultation());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
Expand All @@ -40,7 +41,6 @@
import com.iemr.admin.data.nikshay.NikshayFacility;
import com.iemr.admin.data.nikshay.NikshayState;
import com.iemr.admin.data.nikshay.NikshayTU;
import com.iemr.admin.data.nikshay.NikshayVillage;
import com.iemr.admin.repo.employeemaster.EmployeeMasterRepo;
import com.iemr.admin.repo.nikshay.NikshayDistrictRepo;
import com.iemr.admin.repo.nikshay.NikshayFacilityRepo;
Expand Down Expand Up @@ -121,7 +121,7 @@
OutputResponse response = new OutputResponse();
try {
List<NikshayTU> tus = nikshayTURepo.findByDistrictID(districtID);
response.setResponse(tus.toString());
response.setResponse(new Gson().toJson(tus.stream().map(this::toLite).collect(Collectors.toList())));

Check warning on line 124 in src/main/java/com/iemr/admin/controller/nikshay/NikshayLocationController.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this usage of 'Stream.collect(Collectors.toList())' with 'Stream.toList()' and ensure that the list is unmodified.

See more on https://sonarcloud.io/project/issues?id=PSMRI_Admin-API&issues=AaFcqdeKwC_RT7R0M48U&open=AaFcqdeKwC_RT7R0M48U&pullRequest=155
} catch (Exception e) {
logger.error("Error fetching Nikshay TUs for districtID " + districtID + ": " + e.getMessage(), e);
response.setError(e);
Expand All @@ -136,7 +136,7 @@
try {
List<Integer> ids = parseIntCsv(tuIDs);
List<NikshayFacility> facilities = nikshayFacilityRepo.findByTUIDs(ids);
response.setResponse(facilities.toString());
response.setResponse(new Gson().toJson(facilities.stream().map(this::toLite).collect(Collectors.toList())));

Check warning on line 139 in src/main/java/com/iemr/admin/controller/nikshay/NikshayLocationController.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this usage of 'Stream.collect(Collectors.toList())' with 'Stream.toList()' and ensure that the list is unmodified.

See more on https://sonarcloud.io/project/issues?id=PSMRI_Admin-API&issues=AaFcqdeKwC_RT7R0M48V&open=AaFcqdeKwC_RT7R0M48V&pullRequest=155
} catch (Exception e) {
logger.error("Error fetching Nikshay facilities for tuIDs " + tuIDs + ": " + e.getMessage(), e);
response.setError(e);
Expand All @@ -150,8 +150,8 @@
OutputResponse response = new OutputResponse();
try {
List<Integer> ids = parseIntCsv(facilityIDs);
List<NikshayVillage> villages = nikshayVillageRepo.findByFacilityIDs(ids);
response.setResponse(villages.toString());
List<Object[]> villages = nikshayVillageRepo.findLiteByFacilityIDs(ids);
response.setResponse(new Gson().toJson(villages.stream().map(this::toLiteVillage).collect(Collectors.toList())));

Check warning on line 154 in src/main/java/com/iemr/admin/controller/nikshay/NikshayLocationController.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this usage of 'Stream.collect(Collectors.toList())' with 'Stream.toList()' and ensure that the list is unmodified.

See more on https://sonarcloud.io/project/issues?id=PSMRI_Admin-API&issues=AaFcqdeKwC_RT7R0M48W&open=AaFcqdeKwC_RT7R0M48W&pullRequest=155
} catch (Exception e) {
logger.error("Error fetching villages for facilityIDs " + facilityIDs + ": " + e.getMessage(), e);
response.setError(e);
Expand All @@ -172,8 +172,9 @@
Map<String, Object> result = new HashMap<>();
if (row != null) {
result.put("districtID", row.getDistrictID());
result.put("nikshayTUID", row.getNikshayTUID());

Check failure on line 175 in src/main/java/com/iemr/admin/controller/nikshay/NikshayLocationController.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "nikshayTUID" 3 times.

See more on https://sonarcloud.io/project/issues?id=PSMRI_Admin-API&issues=AaFcqdeKwC_RT7R0M48S&open=AaFcqdeKwC_RT7R0M48S&pullRequest=155
result.put("nikshayFacilityID", row.getNikshayFacilityID());

Check failure on line 176 in src/main/java/com/iemr/admin/controller/nikshay/NikshayLocationController.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "nikshayFacilityID" 3 times.

See more on https://sonarcloud.io/project/issues?id=PSMRI_Admin-API&issues=AaFcqdeKwC_RT7R0M48T&open=AaFcqdeKwC_RT7R0M48T&pullRequest=155
result.put("vanID", row.getVanID());
}
response.setResponse(new Gson().toJson(result));
} catch (Exception e) {
Expand All @@ -183,6 +184,37 @@
return response.toString();
}

// TU/Facility/Village lists can run into thousands of rows for a single
// district (e.g. Pune MC: 5,327 facilities), and the full entities carry
// audit fields (createdBy/createdDate/modifiedBy/lastModDate/codes) the
// Admin UI never reads. Send only the ID, name and parent ID each dropdown
// needs β€” same field names as before, so older UI builds keep working.
private Map<String, Object> toLite(NikshayTU t) {
Map<String, Object> m = new LinkedHashMap<>();
m.put("nikshayTUID", t.getNikshayTUID());
m.put("tUName", t.getTUName());
m.put("nikshayDistrictID", t.getNikshayDistrictID());
return m;
}

private Map<String, Object> toLite(NikshayFacility f) {
Map<String, Object> m = new LinkedHashMap<>();
m.put("nikshayFacilityID", f.getNikshayFacilityID());
m.put("facilityName", f.getFacilityName());
m.put("nikshayTUID", f.getNikshayTUID());
return m;
}

// row = [nikshayVillageID, villageName, nikshayFacilityID], see
// NikshayVillageRepo.findLiteByFacilityIDs
private Map<String, Object> toLiteVillage(Object[] row) {
Map<String, Object> m = new LinkedHashMap<>();
m.put("nikshayVillageID", row[0]);
m.put("villageName", row[1]);
m.put("nikshayFacilityID", row[2]);
return m;
}

private List<Integer> parseIntCsv(String csv) {
return Arrays.stream(csv.split(","))
.map(String::trim)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* AMRIT – Accessible Medical Records via Integrated Technology
* Integrated EHR (Electronic Health Records) Solution
*
* Copyright (C) "Piramal Swasthya Management and Research Institute"
*
* This file is part of AMRIT.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package com.iemr.admin.controller.stoptbteam;

import javax.ws.rs.core.MediaType;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 com.iemr.admin.service.stoptbteam.StopTBTeamService;
import com.iemr.admin.utils.mapper.OutputMapper;
import com.iemr.admin.utils.response.OutputResponse;

import io.swagger.v3.oas.annotations.Operation;

/** Stop TB teams (MMU vans) for Work Location Mapping (AMM-2496). */
@RestController
@RequestMapping(value = "/stoptb/team")
public class StopTBTeamController {
private final Logger logger = LoggerFactory.getLogger(this.getClass().getName());

@Autowired

Check warning on line 46 in src/main/java/com/iemr/admin/controller/stoptbteam/StopTBTeamController.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this field injection and use constructor injection instead.

See more on https://sonarcloud.io/project/issues?id=PSMRI_Admin-API&issues=AaFcqdcgwC_RT7R0M48R&open=AaFcqdcgwC_RT7R0M48R&pullRequest=155
private StopTBTeamService teamService;

@Operation(summary = "Stop TB teams (MMU vans) of a state")
@GetMapping(value = "/vans", produces = MediaType.APPLICATION_JSON)
public String getStateTeams(@RequestParam("stateID") Integer stateID,
@RequestParam("serviceProviderID") Integer serviceProviderID) {
OutputResponse response = new OutputResponse();
try {
response.setResponse(OutputMapper.gsonWithoutExpose().toJson(teamService.stateTeams(stateID, serviceProviderID)));
} catch (Exception e) {
logger.error("Stop TB teams for state {} failed", stateID, e);
response.setError(e);
}
return response.toString();
}

@Operation(summary = "A Stop TB user's current team")
@GetMapping(value = "/user", produces = MediaType.APPLICATION_JSON)
public String getUserTeam(@RequestParam("userID") Integer userID,
@RequestParam("providerServiceMapID") Integer providerServiceMapID) {
OutputResponse response = new OutputResponse();
try {
response.setResponse(OutputMapper.gsonWithoutExpose().toJson(teamService.userTeam(userID, providerServiceMapID)));
} catch (Exception e) {
logger.error("Stop TB team of user {} failed", userID, e);
response.setError(e);
}
return response.toString();
}

@Operation(summary = "Members of a Stop TB team")
@GetMapping(value = "/members", produces = MediaType.APPLICATION_JSON)
public String getTeamMembers(@RequestParam("vanID") Integer vanID,
@RequestParam("providerServiceMapID") Integer providerServiceMapID) {
OutputResponse response = new OutputResponse();
try {
response.setResponse(OutputMapper.gsonWithoutExpose().toJson(teamService.teamMembers(vanID, providerServiceMapID)));
} catch (Exception e) {
logger.error("Stop TB team {} members failed", vanID, e);
response.setError(e);
}
return response.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,12 @@ public class M_UserServiceRoleMapping2 {
@Column(name = "NikshayFacilityID")
private String nikshayFacilityID;

// Stop TB team (AMM-2496): the van (camp laptop) the user works with. Same
// value on all of the user's active Stop TB rows; null when not in a team.
@Expose
@Column(name = "VanID")
private Integer vanID;

public M_UserServiceRoleMapping2() {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,12 @@ public interface NikshayVillageRepo extends CrudRepository<NikshayVillage, Integ

@Query("select v from NikshayVillage v where v.nikshayFacilityID in (:facilityIDs) and v.deleted = false order by v.villageName")
List<NikshayVillage> findByFacilityIDs(@Param("facilityIDs") List<Integer> facilityIDs);

// Only the three columns the village dropdown uses, as [nikshayVillageID,
// villageName, nikshayFacilityID]. A district can have 1 lakh+ village rows
// (the same village repeated under each facility); loading full entities
// for that was most of the response time.
@Query("select v.nikshayVillageID, v.villageName, v.nikshayFacilityID from NikshayVillage v "
+ "where v.nikshayFacilityID in (:facilityIDs) and v.deleted = false order by v.villageName, v.nikshayVillageID")
List<Object[]> findLiteByFacilityIDs(@Param("facilityIDs") List<Integer> facilityIDs);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/*
* AMRIT – Accessible Medical Records via Integrated Technology
* Integrated EHR (Electronic Health Records) Solution
*
* Copyright (C) "Piramal Swasthya Management and Research Institute"
*
* This file is part of AMRIT.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package com.iemr.admin.repository.stoptbteam;

import java.util.List;

import org.springframework.stereotype.Repository;

import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.Query;

/**
* Stop TB teams (AMM-2496). A team is a van; the user's team is the VanID
* on their m_userservicerolemapping rows. Team vans come from one service
* line's vans (MMU today, see stoptb.team.van-service).
*/
@Repository
public class StopTBTeamRepository {
private static String notDeleted(String column) {
return "(" + column + " IS NULL OR " + column + " = b'0')";
}

private static final String STOPTB_SERVICE_LINES =
"SELECT p.ProviderServiceMapID FROM m_providerservicemapping p"
+ " JOIN m_servicemaster s ON s.ServiceID = p.ServiceID WHERE s.ServiceName = 'Stop TB'";

private static final String SELECT_STATE_VANS =
"SELECT v.VanID, v.VanName, v.VehicalNo, v.ParkingPlaceID, pp.ParkingPlaceName"
+ " FROM m_van v"
+ " JOIN m_providerservicemapping p ON p.ProviderServiceMapID = v.ProviderServiceMapID"
+ " JOIN m_servicemaster s ON s.ServiceID = p.ServiceID"
+ " LEFT JOIN m_parkingplace pp ON pp.ParkingPlaceID = v.ParkingPlaceID"
+ " WHERE s.ServiceName = :vanService AND p.StateID = :stateID"
+ " AND p.ServiceProviderID = :serviceProviderID"
+ " AND " + notDeleted("p.Deleted") + " AND " + notDeleted("v.Deleted")

Check failure on line 55 in src/main/java/com/iemr/admin/repository/stoptbteam/StopTBTeamRepository.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal " AND " 3 times.

See more on https://sonarcloud.io/project/issues?id=PSMRI_Admin-API&issues=AaFcqdgFwC_RT7R0M48X&open=AaFcqdgFwC_RT7R0M48X&pullRequest=155
+ " ORDER BY v.VanName, v.VanID";

private static final String SELECT_VAN =
"SELECT v.VanID, p.StateID, p.ServiceProviderID FROM m_van v"
+ " JOIN m_providerservicemapping p ON p.ProviderServiceMapID = v.ProviderServiceMapID"
+ " JOIN m_servicemaster s ON s.ServiceID = p.ServiceID"
+ " WHERE v.VanID = :vanID AND s.ServiceName = :vanService"
+ " AND " + notDeleted("p.Deleted") + " AND " + notDeleted("v.Deleted");

private static final String SELECT_STOPTB_SERVICE =
"SELECT p.StateID, p.ServiceProviderID FROM m_providerservicemapping p"
+ " WHERE p.ProviderServiceMapID = :providerServiceMapID"
+ " AND p.ProviderServiceMapID IN (" + STOPTB_SERVICE_LINES + ")";

private static final String SELECT_USER_TEAM =
"SELECT m.VanID, v.VanName FROM m_userservicerolemapping m"
+ " JOIN m_van v ON v.VanID = m.VanID"
+ " WHERE m.UserID = :userID AND m.ProviderServiceMapID = :providerServiceMapID"
+ " AND " + notDeleted("m.Deleted")
+ " ORDER BY m.LastModDate DESC, m.USRMappingID DESC";

private static final String SELECT_TEAM_MEMBERS =
"SELECT DISTINCT u.UserID, u.UserName, u.FirstName, u.LastName FROM m_userservicerolemapping m"
+ " JOIN m_user u ON u.UserID = m.UserID"
+ " WHERE m.VanID = :vanID AND m.ProviderServiceMapID = :providerServiceMapID"
+ " AND " + notDeleted("m.Deleted") + " AND " + notDeleted("u.Deleted")
+ " ORDER BY u.UserName";

// One team per user: every active Stop TB row of the user gets the same VanID.
private static final String SET_USER_TEAM =
"UPDATE m_userservicerolemapping SET VanID = :vanID"
+ " WHERE UserID = :userID AND ProviderServiceMapID = :providerServiceMapID"
+ " AND " + notDeleted("Deleted")
+ " AND ProviderServiceMapID IN (" + STOPTB_SERVICE_LINES + ")";

@PersistenceContext
private EntityManager entityManager;

/** {VanID, VanName, VehicalNo, ParkingPlaceID, ParkingPlaceName} of the state's team vans. */
@SuppressWarnings("unchecked")
public List<Object[]> stateVans(String vanService, Integer stateID, Integer serviceProviderID) {
return entityManager.createNativeQuery(SELECT_STATE_VANS).setParameter("vanService", vanService)

Check warning on line 97 in src/main/java/com/iemr/admin/repository/stoptbteam/StopTBTeamRepository.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Make sure using a dynamically formatted SQL query is safe here.

See more on https://sonarcloud.io/project/issues?id=PSMRI_Admin-API&issues=AaFcqdgFwC_RT7R0M48a&open=AaFcqdgFwC_RT7R0M48a&pullRequest=155
.setParameter("stateID", stateID).setParameter("serviceProviderID", serviceProviderID)
.getResultList();
}

/** {VanID, StateID, ServiceProviderID} of an active team van, or null. */
public Object[] van(String vanService, Integer vanID) {
return first(entityManager.createNativeQuery(SELECT_VAN).setParameter("vanService", vanService)

Check warning on line 104 in src/main/java/com/iemr/admin/repository/stoptbteam/StopTBTeamRepository.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Make sure using a dynamically formatted SQL query is safe here.

See more on https://sonarcloud.io/project/issues?id=PSMRI_Admin-API&issues=AaFcqdgFwC_RT7R0M48b&open=AaFcqdgFwC_RT7R0M48b&pullRequest=155
.setParameter("vanID", vanID));

Check failure on line 105 in src/main/java/com/iemr/admin/repository/stoptbteam/StopTBTeamRepository.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "vanID" 3 times.

See more on https://sonarcloud.io/project/issues?id=PSMRI_Admin-API&issues=AaFcqdgFwC_RT7R0M48Z&open=AaFcqdgFwC_RT7R0M48Z&pullRequest=155
}

/** {StateID, ServiceProviderID} when the ID is a Stop TB service line, else null. */
public Object[] stopTBService(Integer providerServiceMapID) {
return first(entityManager.createNativeQuery(SELECT_STOPTB_SERVICE)
.setParameter("providerServiceMapID", providerServiceMapID));

Check failure on line 111 in src/main/java/com/iemr/admin/repository/stoptbteam/StopTBTeamRepository.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "providerServiceMapID" 4 times.

See more on https://sonarcloud.io/project/issues?id=PSMRI_Admin-API&issues=AaFcqdgFwC_RT7R0M48Y&open=AaFcqdgFwC_RT7R0M48Y&pullRequest=155
}

/** {VanID, VanName} of the user's team, or null. */
public Object[] userTeam(Integer userID, Integer providerServiceMapID) {
return first(entityManager.createNativeQuery(SELECT_USER_TEAM).setParameter("userID", userID)

Check warning on line 116 in src/main/java/com/iemr/admin/repository/stoptbteam/StopTBTeamRepository.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Make sure using a dynamically formatted SQL query is safe here.

See more on https://sonarcloud.io/project/issues?id=PSMRI_Admin-API&issues=AaFcqdgFwC_RT7R0M48c&open=AaFcqdgFwC_RT7R0M48c&pullRequest=155
.setParameter("providerServiceMapID", providerServiceMapID));
}

/** {UserID, UserName, FirstName, LastName} of the team's members. */
@SuppressWarnings("unchecked")
public List<Object[]> teamMembers(Integer vanID, Integer providerServiceMapID) {
return entityManager.createNativeQuery(SELECT_TEAM_MEMBERS).setParameter("vanID", vanID)

Check warning on line 123 in src/main/java/com/iemr/admin/repository/stoptbteam/StopTBTeamRepository.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Make sure using a dynamically formatted SQL query is safe here.

See more on https://sonarcloud.io/project/issues?id=PSMRI_Admin-API&issues=AaFcqdgFwC_RT7R0M48d&open=AaFcqdgFwC_RT7R0M48d&pullRequest=155
.setParameter("providerServiceMapID", providerServiceMapID).getResultList();
}

/** Puts the user in the team (or none) on all their active Stop TB rows. */
public int setUserTeam(Integer userID, Integer providerServiceMapID, Integer vanID) {
return entityManager.createNativeQuery(SET_USER_TEAM).setParameter("vanID", vanID)

Check warning on line 129 in src/main/java/com/iemr/admin/repository/stoptbteam/StopTBTeamRepository.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Make sure using a dynamically formatted SQL query is safe here.

See more on https://sonarcloud.io/project/issues?id=PSMRI_Admin-API&issues=AaFcqdgFwC_RT7R0M48e&open=AaFcqdgFwC_RT7R0M48e&pullRequest=155
.setParameter("userID", userID).setParameter("providerServiceMapID", providerServiceMapID)
.executeUpdate();
}

private Object[] first(Query query) {
List<?> rows = query.setMaxResults(1).getResultList();
return rows.isEmpty() ? null : (Object[]) rows.get(0);
}
}
Loading
Loading