diff --git a/pom.xml b/pom.xml
index 42c2f42d..29147618 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.iemr.tmtm-api
- 3.6.2
+ 3.8.2warTM-API
diff --git a/src/main/environment/common_ci.properties b/src/main/environment/common_ci.properties
index 2f4cd540..3b96e7a0 100644
--- a/src/main/environment/common_ci.properties
+++ b/src/main/environment/common_ci.properties
@@ -67,6 +67,11 @@ tcSpeclistWL=7
### Redis IP
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 e00511eb..769a8834 100644
--- a/src/main/environment/common_docker.properties
+++ b/src/main/environment/common_docker.properties
@@ -67,6 +67,11 @@ tcSpeclistWL=7
### Redis IP
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 64ac5d63..3e18f9c6 100644
--- a/src/main/environment/common_example.properties
+++ b/src/main/environment/common_example.properties
@@ -69,6 +69,12 @@ prescription=TMPrescription SMS
### Redis IP
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/
logging.file.name=logs/tm-api.log
diff --git a/src/main/java/com/iemr/tm/controller/common/master/CommonMasterController.java b/src/main/java/com/iemr/tm/controller/common/master/CommonMasterController.java
index bda86731..f79d4a75 100644
--- a/src/main/java/com/iemr/tm/controller/common/master/CommonMasterController.java
+++ b/src/main/java/com/iemr/tm/controller/common/master/CommonMasterController.java
@@ -27,7 +27,6 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
diff --git a/src/main/java/com/iemr/tm/controller/login/IemrMmuLoginController.java b/src/main/java/com/iemr/tm/controller/login/IemrMmuLoginController.java
index eb64b2c5..4f4f5947 100644
--- a/src/main/java/com/iemr/tm/controller/login/IemrMmuLoginController.java
+++ b/src/main/java/com/iemr/tm/controller/login/IemrMmuLoginController.java
@@ -46,7 +46,7 @@
@RestController
@RequestMapping(value = "/user", headers = "Authorization", consumes = "application/json", produces = "application/json")
-@PreAuthorize("hasRole('NURSE') || hasRole('PHARMACIST') || hasRole('LABTECHNICIAN') || hasRole('REGISTRAR') || hasRole('DATASYNC') || hasRole('DATA_SYNC') || hasRole('DOCTOR') || hasRole('LAB_TECHNICIAN') || hasRole('TC_SPECIALIST') || hasRole('ONCOLOGIST') || hasRole('RADIOLOGIST') || hasRole('ASHA')")
+@PreAuthorize("hasRole('NURSE') || hasRole('PHARMACIST') || hasRole('LABTECHNICIAN') || hasRole('REGISTRAR') || hasRole('DATASYNC') || hasRole('DATA_SYNC') || hasRole('DOCTOR') || hasRole('LAB_TECHNICIAN') || hasRole('TC_SPECIALIST') || hasRole('ONCOLOGIST') || hasRole('RADIOLOGIST') || hasRole('ASHA') || hasRole('VOLUNTEER') || hasRole('REGISTRATION_OFFICER')")
public class IemrMmuLoginController {
private Logger logger = LoggerFactory.getLogger(RegistrarController.class);
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 5ddcf7ce..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')")
+ @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/registrar/RegistrarServiceImpl.java b/src/main/java/com/iemr/tm/service/registrar/RegistrarServiceImpl.java
index 97d1b7c0..14d735b9 100644
--- a/src/main/java/com/iemr/tm/service/registrar/RegistrarServiceImpl.java
+++ b/src/main/java/com/iemr/tm/service/registrar/RegistrarServiceImpl.java
@@ -112,6 +112,23 @@ public class RegistrarServiceImpl implements RegistrarService {
@Autowired
private CookieUtil cookieUtil;
+ // 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. 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
public void setCommonBenStatusFlowServiceImpl(CommonBenStatusFlowServiceImpl commonBenStatusFlowServiceImpl) {
this.commonBenStatusFlowServiceImpl = commonBenStatusFlowServiceImpl;
@@ -658,7 +675,19 @@ public String registerBeneficiary(String comingRequest, String Authorization) th
Long beneficiaryRegID = null;
Long beneficiaryID = null;
Map responseMap = new HashMap<>();
-
+
+ // 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", vanID);
+ comingRequest = reqJson.toString();
+ } else if (enforceVanID) {
+ throw new Exception(
+ "Camp not configured: stoptb.van.id is 0. Set stoptb.van.id in this deployment's properties file.");
+ }
+
RestTemplate restTemplate = new RestTemplate();
HttpEntity