diff --git a/src/main/java/com/iemr/admin/controller/employeemaster/EmployeeMasterController.java b/src/main/java/com/iemr/admin/controller/employeemaster/EmployeeMasterController.java index 35b6ed6..47dabe9 100644 --- a/src/main/java/com/iemr/admin/controller/employeemaster/EmployeeMasterController.java +++ b/src/main/java/com/iemr/admin/controller/employeemaster/EmployeeMasterController.java @@ -1848,6 +1848,10 @@ public String updateUserRoleMapping(@RequestBody String updateUserRoleMapping, H M_UserServiceRoleMapping2 usrRole = employeeMasterInter.getDataUsrId(pre.getuSRMappingID()); + // Fix 19: capture the DB deleted-flag BEFORE any mutation (this endpoint doesn't change + // it, but the flag must be read before mutation to be meaningful downstream) + boolean wasDeleted = Boolean.TRUE.equals(usrRole.getDeleted()); + // Fix 1/3: cascade asha_supervisor_mapping BEFORE modifying entity to avoid JPA L1 cache issue if (usrRole != null && usrRole.getUserID() != null) { boolean roleChanged = pre.getRoleID() != null && usrRole.getRoleID() != null @@ -1886,7 +1890,7 @@ public String updateUserRoleMapping(@RequestBody String updateUserRoleMapping, H usrRole.setOutbound(pre.getOutbound()); } - M_UserServiceRoleMapping2 savedata = employeeMasterInter.saveRoleMappingeditedData(usrRole, + M_UserServiceRoleMapping2 savedata = employeeMasterInter.saveRoleMappingeditedData(usrRole, wasDeleted, request.getHeader("Authorization")); response.setResponse(savedata.toString()); @@ -1916,11 +1920,16 @@ public String deleteUserRoleMapping(@RequestBody String deletedUserRoleMapping, M_UserServiceRoleMapping2 usrRole = employeeMasterInter.getDataUsrId(pre.getuSRMappingID()); + // Fix 19: capture the DB deleted-flag BEFORE any mutation, so saveRoleMappingeditedData + // can tell a reactivation apart from a fresh create/update without re-fetching (which + // would hit the JPA L1 cache and return this same already-mutated instance). + boolean wasDeleted = Boolean.TRUE.equals(usrRole.getDeleted()); + // Fix 2: cascade asha_supervisor_mapping BEFORE setDeleted() to avoid JPA L1 cache issue. // After setDeleted(true), findById() in saveRoleMappingeditedData hits the L1 cache // returning the already-modified entity, so the "old vs new deleted" check always fails. // For ASHA Supervisor with multiple facilities: only delete mappings for this facilityID - if (Boolean.TRUE.equals(pre.getDeleted()) && !Boolean.TRUE.equals(usrRole.getDeleted()) + if (Boolean.TRUE.equals(pre.getDeleted()) && !wasDeleted && usrRole.getUserID() != null) { logger.info("Fix2: cascading asha_supervisor_mapping soft-delete for userID={}, uSRMappingID={}", usrRole.getUserID(), pre.getuSRMappingID()); @@ -1929,7 +1938,7 @@ public String deleteUserRoleMapping(@RequestBody String deletedUserRoleMapping, usrRole.setDeleted(pre.getDeleted()); - M_UserServiceRoleMapping2 savedata = employeeMasterInter.saveRoleMappingeditedData(usrRole, + M_UserServiceRoleMapping2 savedata = employeeMasterInter.saveRoleMappingeditedData(usrRole, wasDeleted, request.getHeader("Authorization")); response.setResponse(savedata.toString()); diff --git a/src/main/java/com/iemr/admin/service/employeemaster/EmployeeMasterInter.java b/src/main/java/com/iemr/admin/service/employeemaster/EmployeeMasterInter.java index 81b5f45..d1aa0e2 100644 --- a/src/main/java/com/iemr/admin/service/employeemaster/EmployeeMasterInter.java +++ b/src/main/java/com/iemr/admin/service/employeemaster/EmployeeMasterInter.java @@ -161,7 +161,10 @@ Boolean checkingEmpDetails(String userName, String aadhaarNo, String getpAN, Str M_UserServiceRoleMapping2 getDataUsrId(Integer uSRMappingID); // M_UserServiceRoleMapping2 saveRoleMappingeditedData(M_UserServiceRoleMapping2 usrRole, String string); - public M_UserServiceRoleMapping2 saveRoleMappingeditedData(M_UserServiceRoleMapping2 usrRole, String authToken) throws JsonMappingException, JsonProcessingException; + // wasDeleted: the row's deleted flag as read from the DB BEFORE the caller mutated usrRole. + // Must be captured by the caller before mutation — a re-fetch here would hit the JPA L1 cache + // and return the already-mutated instance (Open-Session-In-View keeps one L1 cache per request). + public M_UserServiceRoleMapping2 saveRoleMappingeditedData(M_UserServiceRoleMapping2 usrRole, boolean wasDeleted, String authToken) throws JsonMappingException, JsonProcessingException; // Fix 2: cascade soft-delete asha_supervisor_mapping rows when a user is deactivated void cascadeDeleteAshaMappingsForUser(Integer userID); diff --git a/src/main/java/com/iemr/admin/service/employeemaster/EmployeeMasterServiceImpl.java b/src/main/java/com/iemr/admin/service/employeemaster/EmployeeMasterServiceImpl.java index f4c07f3..5432ba5 100644 --- a/src/main/java/com/iemr/admin/service/employeemaster/EmployeeMasterServiceImpl.java +++ b/src/main/java/com/iemr/admin/service/employeemaster/EmployeeMasterServiceImpl.java @@ -1043,16 +1043,26 @@ public void cascadeDeleteAshaMappingsForDeactivation(M_UserServiceRoleMapping2 u } @Override - public M_UserServiceRoleMapping2 saveRoleMappingeditedData(M_UserServiceRoleMapping2 usrRole, String authToken) throws JsonMappingException, JsonProcessingException { - - // Fix 4 + Fix 16 + Fix 17 + Fix 14: validate only on create/update, skip for deactivation + public M_UserServiceRoleMapping2 saveRoleMappingeditedData(M_UserServiceRoleMapping2 usrRole, boolean wasDeleted, String authToken) throws JsonMappingException, JsonProcessingException { + + // Fix 4 + Fix 16 + Fix 17 + Fix 14: validate only on create/update, skip entirely for deactivation. + // Fix 19: on reactivation, waive ONLY Fix 4 (facility-mandatory) — legacy ASHA rows created + // before this rule existed may have no facility, and reactivation alone shouldn't be blocked + // by that. Fix 16/17 must still run whenever a facility IS present (reactivation or not), so + // a reactivated row can't silently resume pointing at a facility that went stale (soft-deleted, + // or no longer SC-level) while the user was inactive. + // wasDeleted is captured by the caller BEFORE usrRole is mutated — re-fetching it here via + // findById() would return the same JPA-managed instance as usrRole (Open-Session-In-View + // keeps one L1 cache per request), which already reflects the new (mutated) state. M_Role role = null; + boolean isReactivation = usrRole.getuSRMappingID() != null && wasDeleted + && Boolean.FALSE.equals(usrRole.getDeleted()); if (!Boolean.TRUE.equals(usrRole.getDeleted())) { if (usrRole.getRoleID() != null) { role = roleRepo.findByRoleID(usrRole.getRoleID()); - // Fix 4: ASHA must have a facilityID + // Fix 4: ASHA must have a facilityID (waived on reactivation of a legacy row) if (role != null && "asha".equalsIgnoreCase(role.getRoleName()) - && usrRole.getFacilityID() == null) { + && usrRole.getFacilityID() == null && !isReactivation) { throw new RuntimeException( "Facility (SC) is mandatory for ASHA role. Please select a facility before saving."); }