diff --git a/pom.xml b/pom.xml
index 7075ac9b..8bb278fd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.iemr.tm
tm-api
- 3.8.3
+ 3.12.0
war
TM-API
diff --git a/src/main/environment/common_ci.properties b/src/main/environment/common_ci.properties
index 8965154b..4d28e591 100644
--- a/src/main/environment/common_ci.properties
+++ b/src/main/environment/common_ci.properties
@@ -70,6 +70,8 @@ spring.redis.host=@env.REDIS_HOST@
# Stop TB: when true, beneficiary registration fails with an error if camp (vanID) is not configured
stoptb.enforce.vanid=@env.STOPTB_ENFORCE_VANID@
+# Stop TB: this deployment's van/camp ID, replacing the old Redis camp:vanID lookup
+stoptb.van.id=@env.STOPTB_VAN_ID@
jwt.secret=@env.JWT_SECRET_KEY@
diff --git a/src/main/environment/common_docker.properties b/src/main/environment/common_docker.properties
index c7f85e37..62c6e890 100644
--- a/src/main/environment/common_docker.properties
+++ b/src/main/environment/common_docker.properties
@@ -70,6 +70,8 @@ spring.redis.host=${REDIS_HOST}
# Stop TB: when true, beneficiary registration fails with an error if camp (vanID) is not configured
stoptb.enforce.vanid=${STOPTB_ENFORCE_VANID}
+# Stop TB: this deployment's van/camp ID, replacing the old Redis camp:vanID lookup
+stoptb.van.id=${STOPTB_VAN_ID}
jwt.secret=${JWT_SECRET_KEY}
#ELK logging file name
diff --git a/src/main/environment/common_example.properties b/src/main/environment/common_example.properties
index 5f986124..c7e439a1 100644
--- a/src/main/environment/common_example.properties
+++ b/src/main/environment/common_example.properties
@@ -72,6 +72,8 @@ spring.redis.host=localhost
# Stop TB: when true, beneficiary registration fails with an error if camp (vanID)
# is not configured instead of silently registering without it
stoptb.enforce.vanid=false
+# Stop TB: this deployment's van/camp ID, replacing the old Redis camp:vanID lookup
+stoptb.van.id=0
jwt.secret=my-32-character-ultra-secure-and-ultra-long-secret
logging.path=logs/
diff --git a/src/main/java/com/iemr/tm/controller/registrar/main/RegistrarController.java b/src/main/java/com/iemr/tm/controller/registrar/main/RegistrarController.java
index fe16cb0f..832ef393 100644
--- a/src/main/java/com/iemr/tm/controller/registrar/main/RegistrarController.java
+++ b/src/main/java/com/iemr/tm/controller/registrar/main/RegistrarController.java
@@ -399,7 +399,7 @@ public String createBeneficiary(
// beneficiary registration with common and identity new
@Operation(summary = "Register a new beneficiary new API")
@PostMapping(value = { "/registrarBeneficaryRegistrationNew" })
- @PreAuthorize("hasRole('NURSE') || hasRole('REGISTRAR') || hasRole('ASHA') || hasRole('VOLUNTEER') || hasRole('REGISTRATION_OFFICER')")
+ @PreAuthorize("hasRole('NURSE') || hasRole('REGISTRAR') || hasRole('ASHA') || hasRole('VOLUNTEER') || hasRole('REGISTRATION_OFFICER') || hasRole('COUNSELLOR')")
public String registrarBeneficaryRegistrationNew(@RequestBody String comingReq,
@RequestHeader(value = "Authorization") String Authorization) {
String s;
diff --git a/src/main/java/com/iemr/tm/repo/benFlowStatus/BeneficiaryFlowStatusRepo.java b/src/main/java/com/iemr/tm/repo/benFlowStatus/BeneficiaryFlowStatusRepo.java
index 579f7631..58b50dc6 100644
--- a/src/main/java/com/iemr/tm/repo/benFlowStatus/BeneficiaryFlowStatusRepo.java
+++ b/src/main/java/com/iemr/tm/repo/benFlowStatus/BeneficiaryFlowStatusRepo.java
@@ -44,6 +44,32 @@
public interface BeneficiaryFlowStatusRepo extends CrudRepository {
+ // Targeted update — touches ONLY vanSerialNo. A full-entity save() here would also
+ // rewrite every other updatable column (e.g. `deleted`, which is insertable=false but
+ // NOT updatable=false) with whatever stale value the in-memory Java object happens to
+ // hold, silently clobbering the DB's own DEFAULT for columns never explicitly set.
+ @Transactional
+ @Modifying
+ @Query("UPDATE BeneficiaryFlowStatus t SET t.vanSerialNo = :vanSerialNo WHERE t.benFlowID = :id")
+ void updateVanSerialNo(@Param("id") Long id, @Param("vanSerialNo") Long vanSerialNo);
+
+ // Stop TB's district/village IDs are Nikshay-scoped, not AMRIT's general m_district/
+ // m_village numbering - the two ID spaces overlap (e.g. ID 1 means "Nicobars" in
+ // m_district but "Alluri Sitharama Raju" in m_nikshay_district), so client-sent text
+ // for these IDs can silently land on the wrong scheme's name. Gate any Nikshay-table
+ // resolution on this check first - a PSM with no Nikshay TU mapping is a non-Stop-TB
+ // program (ANC/NCD/cancer-screening/etc.) and must NOT go through the Nikshay tables.
+ @Query(value = "SELECT COUNT(*) FROM m_userservicerolemapping "
+ + "WHERE ProviderServiceMapID = :psmId AND NikshayTUID IS NOT NULL AND Deleted = false LIMIT 1",
+ nativeQuery = true)
+ int countNikshayMappedUsersForPSM(@Param("psmId") Integer psmId);
+
+ @Query(value = "SELECT DistrictName FROM m_nikshay_district WHERE NikshayDistrictID = :id", nativeQuery = true)
+ String getNikshayDistrictName(@Param("id") Integer id);
+
+ @Query(value = "SELECT VillageName FROM m_nikshay_village WHERE NikshayVillageID = :id", nativeQuery = true)
+ String getNikshayVillageName(@Param("id") Integer id);
+
// nurse worklist
// @Query("SELECT t from BeneficiaryFlowStatus t WHERE (t.nurseFlag = 1 OR t.nurseFlag = 100) AND (t.specialist_flag <> 100 OR t.specialist_flag is null) AND t.deleted = false "
// + " AND Date(t.visitDate) = curdate() AND t.providerServiceMapId = :providerServiceMapId "
diff --git a/src/main/java/com/iemr/tm/service/benFlowStatus/CommonBenStatusFlowServiceImpl.java b/src/main/java/com/iemr/tm/service/benFlowStatus/CommonBenStatusFlowServiceImpl.java
index d905a7a7..fd923f70 100644
--- a/src/main/java/com/iemr/tm/service/benFlowStatus/CommonBenStatusFlowServiceImpl.java
+++ b/src/main/java/com/iemr/tm/service/benFlowStatus/CommonBenStatusFlowServiceImpl.java
@@ -64,12 +64,24 @@ public int createBenFlowRecord(String requestOBJ, Long beneficiaryRegID, Long be
int returnOBJ = 0;
try {
BeneficiaryFlowStatus obj = getBenFlowRecordObj(requestOBJ, beneficiaryRegID, beneficiaryID);
+ System.out.println("TRACE createBenFlowRecord: benRegID=" + obj.getBeneficiaryRegID()
+ + " providerServiceMapID=" + obj.getProviderServiceMapID()
+ + " villageID=" + obj.getVillageID()
+ + " vanID=" + obj.getVanID());
if (beneficiaryRegID != null && beneficiaryID != null && beneficiaryRegID > 0 && beneficiaryID > 0) {
objRS = beneficiaryFlowStatusRepo.save(obj);
- if (objRS != null)
+ if (objRS != null) {
+ // VanSerialNo was never populated for i_ben_flow_outreach — following the
+ // same convention used elsewhere (VanSerialNo = record's own local PK, e.g.
+ // IdentityService.regMap.setVanSerialNo(regMap.getBenRegId())).
+ // A full-entity save() here (as this used to do) would also rewrite `deleted`
+ // (insertable=false but NOT updatable=false) with the in-memory object's never-set
+ // null, clobbering the DB's own DEFAULT b'0' and making the row invisible to every
+ // worklist query filtering `deleted = false` — use a targeted UPDATE instead.
+ beneficiaryFlowStatusRepo.updateVanSerialNo(objRS.getBenFlowID(), objRS.getBenFlowID());
returnOBJ = 1;
- else
+ } else
returnOBJ = 0;
} else {
Calendar cal = Calendar.getInstance();
@@ -85,9 +97,11 @@ public int createBenFlowRecord(String requestOBJ, Long beneficiaryRegID, Long be
returnOBJ = 3;
} else {
objRS = beneficiaryFlowStatusRepo.save(obj);
- if (objRS != null)
+ if (objRS != null) {
+ objRS.setVanSerialNo(objRS.getBenFlowID());
+ objRS = beneficiaryFlowStatusRepo.save(objRS);
returnOBJ = 1;
- else
+ } else
returnOBJ = 0;
}
@@ -154,6 +168,34 @@ private BeneficiaryFlowStatus getBenFlowRecordObj(String requestOBJ, Long benefi
if (obj.getI_bendemographics().getDistrictBranchName() != null)
obj.setVillageName(obj.getI_bendemographics().getDistrictBranchName());
+ // Stop TB's district/village IDs are Nikshay-scoped, not AMRIT's general m_district/
+ // m_village numbering - the same numeric ID can mean two different real places
+ // depending on the scheme, so the client-sent name text can silently be wrong.
+ // Only override for PSMs actually mapped to a Nikshay TU (i.e. genuinely Stop TB) -
+ // every other program (ANC/NCD/cancer-screening/etc.) keeps using client-sent text
+ // as before, since their IDs are correctly AMRIT-scoped already.
+ try {
+ if (obj.getProviderServiceMapID() != null
+ && beneficiaryFlowStatusRepo.countNikshayMappedUsersForPSM(obj.getProviderServiceMapID()) > 0) {
+ if (obj.getDistrictID() != null) {
+ String correctDistrictName = beneficiaryFlowStatusRepo.getNikshayDistrictName(obj.getDistrictID());
+ if (correctDistrictName != null) {
+ obj.setDistrictName(correctDistrictName);
+ }
+ }
+ if (obj.getVillageID() != null) {
+ String correctVillageName = beneficiaryFlowStatusRepo.getNikshayVillageName(obj.getVillageID());
+ if (correctVillageName != null) {
+ obj.setVillageName(correctVillageName);
+ }
+ }
+ }
+ } catch (Exception e) {
+ // Never let a Nikshay-name lookup failure block registration - worst case the
+ // display text stays whatever the client sent, same as before this fix existed.
+ logger.warn("Nikshay district/village name resolution failed, keeping client-sent text: " + e.getMessage());
+ }
+
if (obj.getI_bendemographics().getServicePointID() != null)
obj.setServicePointID(obj.getI_bendemographics().getServicePointID());
if (obj.getI_bendemographics().getServicePointName() != null)
diff --git a/src/main/java/com/iemr/tm/service/common/master/ANCMasterDataServiceImpl.java b/src/main/java/com/iemr/tm/service/common/master/ANCMasterDataServiceImpl.java
index 8f5e7136..6312b712 100644
--- a/src/main/java/com/iemr/tm/service/common/master/ANCMasterDataServiceImpl.java
+++ b/src/main/java/com/iemr/tm/service/common/master/ANCMasterDataServiceImpl.java
@@ -26,6 +26,7 @@
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.google.gson.Gson;
@@ -163,6 +164,10 @@ public class ANCMasterDataServiceImpl {
private RouteOfAdminRepo routeOfAdminRepo;
private V_DrugPrescriptionRepo v_DrugPrescriptionRepo;
+ // This deployment's camp van; same property RegistrarServiceImpl uses. 0 = not a camp server.
+ @Value("${stoptb.van.id}")
+ private int campVanID;
+
@Autowired
private CovidSymptomsMasterRepo covidSymptomsMasterRepo;
@Autowired
@@ -560,6 +565,12 @@ public String getCommonDoctorMasterDataForGenopdAncNcdcarePnc(Integer visitCateg
NonedlList.get(i).setUnitOfMeasurement(NonedlList.get(i).getUom().getuOMName());
}
ArrayList itemList = new ArrayList<>();
+ // Stop TB camp: the deployment's van (stoptb.van.id) decides the store, whatever van/facility the
+ // app sends. Servers without a camp van (stoptb.van.id=0) keep using the request values.
+ if (campVanID > 0) {
+ vanID = campVanID;
+ facilityID = null;
+ }
if (facilityID == null || facilityID <= 0) {
Integer fID = masterVanRepo.getFacilityID(vanID);
if (fID != null && fID > 0)
diff --git a/src/main/java/com/iemr/tm/service/registrar/RegistrarServiceImpl.java b/src/main/java/com/iemr/tm/service/registrar/RegistrarServiceImpl.java
index 688f3765..14d735b9 100644
--- a/src/main/java/com/iemr/tm/service/registrar/RegistrarServiceImpl.java
+++ b/src/main/java/com/iemr/tm/service/registrar/RegistrarServiceImpl.java
@@ -40,8 +40,6 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
-import org.springframework.data.redis.connection.RedisConnection;
-import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
@@ -114,12 +112,21 @@ public class RegistrarServiceImpl implements RegistrarService {
@Autowired
private CookieUtil cookieUtil;
- @Autowired
- private LettuceConnectionFactory redisConnectionFactory;
+ // This deployment's van/camp ID. Previously looked up from Redis ("camp:vanID"),
+ // written at MMU login and deleted (globally, unscoped) on ANY user's logout — a Redis
+ // outage or an unrelated user's logout would silently break registration on this camp.
+ // Each camp/van already runs its own dedicated backend instance, so which van this is
+ // never actually changes at runtime; reading it from properties removes the Redis
+ // dependency entirely. No inline default — every properties file must set this
+ // explicitly. Scope: vanID only, parkingPlaceID is not part of this change.
+ @Value("${stoptb.van.id}")
+ private int vanID;
// When true, beneficiary registration fails loudly if camp is not configured
- // instead of silently registering with vanID unset
- @Value("${stoptb.enforce.vanid:false}")
+ // instead of silently registering with vanID unset. No inline default — every
+ // properties file must set this explicitly, so a forgotten config fails loudly
+ // at startup instead of running fail-open.
+ @Value("${stoptb.enforce.vanid}")
private boolean enforceVanID;
@Autowired
@@ -669,26 +676,16 @@ public String registerBeneficiary(String comingRequest, String Authorization) th
Long beneficiaryID = null;
Map responseMap = new HashMap<>();
- // Inject correct vanID from Redis (mobile sends vanID=0 as placeholder)
- byte[] vanIDBytes = null;
- byte[] ppIDBytes = null;
- try {
- RedisConnection conn = redisConnectionFactory.getConnection();
- vanIDBytes = conn.get("camp:vanID".getBytes());
- ppIDBytes = conn.get("camp:parkingPlaceID".getBytes());
- conn.close();
- } catch (Exception e) {
- logger.warn("Camp vanID lookup failed: " + e.getMessage());
- }
- if (vanIDBytes != null) {
+ // Inject configured vanID (mobile sends vanID=0 as placeholder). Previously looked
+ // up from Redis at request time; now a fixed property of this deployment (see
+ // vanID field javadoc above).
+ if (vanID > 0) {
JSONObject reqJson = new JSONObject(comingRequest);
- reqJson.put("vanID", Integer.parseInt(new String(vanIDBytes)));
- if (ppIDBytes != null)
- reqJson.put("parkingPlaceID", Integer.parseInt(new String(ppIDBytes)));
+ reqJson.put("vanID", vanID);
comingRequest = reqJson.toString();
} else if (enforceVanID) {
throw new Exception(
- "Camp not configured: vanID missing. Please select van/service point in MMU before registering beneficiary.");
+ "Camp not configured: stoptb.van.id is 0. Set stoptb.van.id in this deployment's properties file.");
}
RestTemplate restTemplate = new RestTemplate();
@@ -710,13 +707,19 @@ public String registerBeneficiary(String comingRequest, String Authorization) th
responseMap.put("benRegId", beneficiaryRegID);
BeneficiaryFlowStatus obj = InputMapper.gson().fromJson(comingRequest, BeneficiaryFlowStatus.class);
+ System.out.println("TRACE registerBeneficiary: benRegID=" + beneficiaryRegID + " isMobile="
+ + (obj != null ? obj.getIsMobile() : "obj=null") + " providerServiceMapID="
+ + (obj != null ? obj.getProviderServiceMapID() : null) + " villageID="
+ + (obj != null ? obj.getVillageID() : null));
if (obj != null && obj.getIsMobile() != null && obj.getIsMobile()) {
+ System.out.println("TRACE registerBeneficiary: isMobile=true branch — createBenFlowRecord SKIPPED, benRegID=" + beneficiaryRegID);
responseMap.put("response", "Beneficiary successfully registered. Beneficiary ID is : "+ beneficiaryID+" , BenRegID is : "+beneficiaryRegID);
response1.setResponse(new Gson().toJson(responseMap));
} else {
int i = commonBenStatusFlowServiceImpl.createBenFlowRecord(comingRequest, beneficiaryRegID,
beneficiaryID);
+ System.out.println("TRACE registerBeneficiary: createBenFlowRecord returned=" + i + " benRegID=" + beneficiaryRegID);
if (i > 0) {
responseMap.put("response", "Beneficiary successfully registered. Beneficiary ID is : "+ beneficiaryID+" , BenRegID is : "+beneficiaryRegID);