diff --git a/src/main/java/com/iemr/flw/dto/iemr/UserServiceRoleDTO.java b/src/main/java/com/iemr/flw/dto/iemr/UserServiceRoleDTO.java index ead3ddc0..c336e1c9 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/UserServiceRoleDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/UserServiceRoleDTO.java @@ -27,6 +27,14 @@ public class UserServiceRoleDTO { private String villageName; private Map facilityData; + // Stop TB / Nikshay location scope — populated only when serviceName = "Stop TB". + // Set via setters after construction (additive, not part of the base constructor + // so every other service line's DTO construction stays exactly as it is today). + private String tuId; + private String tuName; + private String healthFacilityId; + private String healthFacilityName; + public UserServiceRoleDTO(Integer userId, String name, String userName, Integer stateId, String stateName, Integer workingDistrictId, String workingDistrictName, Short serviceProviderId, Integer roleId, String roleName, Integer providerServiceMapId, Integer blockId, String blockName, String villageId, String villageName) { this.userId = userId; this.name = name; diff --git a/src/main/java/com/iemr/flw/repo/iemr/UserServiceRoleRepo.java b/src/main/java/com/iemr/flw/repo/iemr/UserServiceRoleRepo.java index d2cdc2f4..95733b8a 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/UserServiceRoleRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/UserServiceRoleRepo.java @@ -79,4 +79,10 @@ List getNikshayMappingRows(@Param("userId") Integer userId, @Query(value = "SELECT DistrictName FROM m_nikshay_district WHERE NikshayDistrictID = :id", nativeQuery = true) String findNikshayDistrictName(@Param("id") Integer id); + @Query("SELECT new com.iemr.flw.dto.iemr.UserServiceRoleDTO(u.userId, u.name, u.userName, u.stateId, u.stateName, u.workingDistrictId," + + "u.workingDistrictName, u.serviceProviderId, u.roleId, u.roleName, u.providerServiceMapId, u.blockid, u.blockname, u.villageid, " + + "u.villagename) FROM UserServiceRole u WHERE u.userId IN :userIds " + + "AND u.userServciceRoleDeleted = false AND u.userDeleted = false") + List getUserRolesByIds(@Param("userIds") List userIds); + } diff --git a/src/main/java/com/iemr/flw/service/TBConfirmedCaseService.java b/src/main/java/com/iemr/flw/service/TBConfirmedCaseService.java index b1d4165e..67ca9e1a 100644 --- a/src/main/java/com/iemr/flw/service/TBConfirmedCaseService.java +++ b/src/main/java/com/iemr/flw/service/TBConfirmedCaseService.java @@ -1,6 +1,8 @@ package com.iemr.flw.service; import com.iemr.flw.domain.iemr.TBConfirmedCaseDTO; +import com.iemr.flw.dto.iemr.TbReferralFollowUpDTO; +import com.iemr.flw.dto.iemr.TbTptFollowUpDTO; import org.springframework.stereotype.Service; import java.util.List; @@ -18,4 +20,12 @@ public interface TBConfirmedCaseService { // One record per row, in the same JSON shape getAll returns (STOP-TB changes feed), keyed by id. java.util.Map getRecordsByIds(java.util.Collection ids); + + String saveReferralFollowUp(TbReferralFollowUpDTO requestDTO, String token); + + String getReferralFollowUp(String token); + + String saveTptFollowUp(TbTptFollowUpDTO requestDTO, String token); + + String getTptFollowUp(String token); } diff --git a/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java index 2db58ede..133f46f3 100644 --- a/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java @@ -1,15 +1,15 @@ package com.iemr.flw.service.impl; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.iemr.flw.domain.iemr.DynamicForm; -import com.iemr.flw.domain.iemr.TBConfirmedCaseDTO; -import com.iemr.flw.domain.iemr.TBConfirmedCase; -import com.iemr.flw.domain.iemr.BenVisitDetail; +import com.iemr.flw.domain.iemr.*; +import com.iemr.flw.dto.iemr.TbReferralFollowUpDTO; +import com.iemr.flw.dto.iemr.TbReferralFollowUpListDTO; +import com.iemr.flw.dto.iemr.TbTptFollowUpDTO; +import com.iemr.flw.dto.iemr.TbTptFollowUpListDTO; import com.iemr.flw.repo.identity.BeneficiaryRepo; -import com.iemr.flw.repo.iemr.DynamicFormRepo; -import com.iemr.flw.repo.iemr.FormResponseRepo; -import com.iemr.flw.repo.iemr.TBConfirmedTreatmentRepository; +import com.iemr.flw.repo.iemr.*; import com.iemr.flw.seeder.TbCounsellingV2FormSeeder; import com.iemr.flw.service.IncentiveLogicService; import com.iemr.flw.service.CampConfigService; @@ -25,12 +25,9 @@ import java.sql.Timestamp; import java.time.LocalDate; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.*; import java.util.stream.Collectors; @Service @@ -57,6 +54,15 @@ public class TBConfirmedCaseServiceImpl implements TBConfirmedCaseService { @Autowired private BeneficiaryRepo beneficiaryRepo; + @Autowired + private TbReferralFollowUpRepo tbReferralFollowUpRepo; + + @Autowired + private IncentiveLogicImpl incentiveLogic; + + @Autowired + private TbTptFollowUpRepo tbTptFollowUpRepo; + public TBConfirmedCaseServiceImpl(TBConfirmedTreatmentRepository repository, FormResponseRepo formResponseRepo, DynamicFormRepo dynamicFormRepo) { @@ -141,21 +147,37 @@ private void checkIncentive(TBConfirmedCase entity){ || "Longer Regimen (18–24 Months)".equalsIgnoreCase(regimen); if (Boolean.TRUE.equals(entity.getTreatmentCompleted()) - && entity.getExpectedTreatmentCompletionDate() != null) { + && entity.getFollowUpDate() != null) { if (isDrTb) { - incentiveLogicService.incentiveForTbFollowUpIsDrTb( - entity.getBenId(), - Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), - Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), - entity.getUserId() - ); + if("Shorter Regimen (9–12 Months)".equalsIgnoreCase(regimen)){ + if ("cured".equalsIgnoreCase(entity.getTreatmentOutcome())) { + incentiveLogicService.incentiveForTbFollowUpIsDrTb( + entity.getBenId(), + Timestamp.valueOf(entity.getFollowUpDate().atStartOfDay()), + Timestamp.valueOf(entity.getFollowUpDate().atStartOfDay()), + entity.getUserId() + ); + } + + }else if("Longer Regimen (18–24 Months)".equalsIgnoreCase(regimen)){ + if ("cured".equalsIgnoreCase(entity.getTreatmentOutcome())) { + + incentiveLogicService.incentiveForTbFollowUpIsDrTb( + entity.getBenId(), + Timestamp.valueOf(entity.getFollowUpDate().atStartOfDay()), + Timestamp.valueOf(entity.getFollowUpDate().atStartOfDay()), + entity.getUserId() + ); + } + } + } else { incentiveLogicService.incentiveForTbFollowUp( entity.getBenId(), - Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), - Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), + Timestamp.valueOf(entity.getFollowUpDate().atStartOfDay()), + Timestamp.valueOf(entity.getFollowUpDate().atStartOfDay()), entity.getUserId() ); @@ -164,6 +186,24 @@ private void checkIncentive(TBConfirmedCase entity){ } } + public boolean isEligibleForIncentive(LocalDate treatmentStartDate, LocalDate endDate,Integer minMonth) { + + if (treatmentStartDate == null || endDate == null) { + return false; + } + + LocalDate start = treatmentStartDate.atStartOfDay() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + + LocalDate end = endDate.atStartOfDay() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + + return end.isAfter(start.plusMonths(minMonth)) + || end.isEqual(start.plusMonths(minMonth)); + } + @Override public String getByBenId(Long benId, String authorisation) throws Exception { OutputResponse response = new OutputResponse(); @@ -215,6 +255,429 @@ public Map getRecordsByIds(java.util.Collection ids) { return out; } + @Override + public String saveReferralFollowUp(TbReferralFollowUpDTO requestDTO, String token) { + OutputResponse response = new OutputResponse(); + + try { + + TbReferralFollowUp tbReferralFollowUp = new TbReferralFollowUp(); + + if(!token.isEmpty() && token!=null && requestDTO!=null){ + String userName = jwtUtil.extractUsername(token); + Integer userId = jwtUtil.extractUserId(token); + tbReferralFollowUp.setBenId(requestDTO.getBenId()); + tbReferralFollowUp.setHouseHoldId(requestDTO.getHouseHoldId()); + tbReferralFollowUp.setSyncedBy(userName); + tbReferralFollowUp.setUpdatedBy(userName); + tbReferralFollowUp.setCreatedBy(userName); + tbReferralFollowUp.setUserId(userId); + if(requestDTO.getFields().getReferredOnDate()!=null && !requestDTO.getFields().getFollowUpDate().isEmpty()){ + Timestamp referOnDate = Timestamp.valueOf(requestDTO.getFields().getReferredOnDate()); + tbReferralFollowUp.setFollowUpDate(referOnDate); + + } + + if(requestDTO.getFields().getFollowUpDate()!=null && !requestDTO.getFields().getFollowUpDate().isEmpty()){ + Timestamp followUpDate = Timestamp.valueOf(requestDTO.getFields().getFollowUpDate()); + tbReferralFollowUp.setFollowUpDate(followUpDate); + + } + tbReferralFollowUp.setFollowUpStatus(requestDTO.getFields().getFollowUpStatus()); + } + + tbReferralFollowUpRepo.save(tbReferralFollowUp); + response.setResponse("TB Referral follow up saved successfully"); + + + + }catch (Exception e){ + response.setError(500,e.getMessage()); + return response.toString(); + } + + + return response.toString(); + } + + @Override + public String getReferralFollowUp(String token) { + OutputResponse response = new OutputResponse(); + + try { + if (token == null || token.trim().isEmpty()) { + response.setError(400, "Token is required"); + return response.toString(); + } + + Integer userId = jwtUtil.extractUserId(token); + + List referrals = + tbReferralFollowUpRepo.findByUserId(userId); + + List referralDTOs = new ArrayList<>(); + + DateTimeFormatter formatter = + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + for (TbReferralFollowUp referral : referrals) { + + TbReferralFollowUpDTO dto = new TbReferralFollowUpDTO(); + dto.setBenId(referral.getBenId()); + dto.setUserId(referral.getUserId()); + dto.setHouseHoldId(referral.getHouseHoldId()); + + // Initialize nested DTO before setting fields + TbReferralFollowUpListDTO fields = + new TbReferralFollowUpListDTO(); + + if (referral.getReferredOnDate() != null) { + fields.setReferredOnDate( + referral.getReferredOnDate() + .toLocalDateTime() + .format(formatter) + ); + } + + if (referral.getFollowUpDate() != null) { + fields.setFollowUpDate( + referral.getFollowUpDate() + .toLocalDateTime() + .format(formatter) + ); + } + + fields.setFollowUpStatus(referral.getFollowUpStatus()); + + dto.setFields(fields); + referralDTOs.add(dto); + } + + ObjectMapper objectMapper = new ObjectMapper(); + + response.setResponse( + objectMapper.writeValueAsString(referralDTOs) + ); + + } catch (Exception e) { + // Replace with your project's logger if available + e.printStackTrace(); + response.setError(500, "Failed to fetch referral follow-up: " + e.getMessage()); + } + + return response.toString(); + } + + @Override + public String saveTptFollowUp(TbTptFollowUpDTO requestDTO, String token) { + + OutputResponse response = new OutputResponse(); + + try { + + TbTptFollowUp tbTptFollowUp = new TbTptFollowUp(); + + if (token != null && !token.isEmpty() && requestDTO != null) { + + String userName = jwtUtil.extractUsername(token); + Integer userId = jwtUtil.extractUserId(token); + + tbTptFollowUp.setBenId(requestDTO.getBenId()); + tbTptFollowUp.setUserId(userId); + + tbTptFollowUp.setCreatedBy(userName); + tbTptFollowUp.setUpdatedBy(userName); + + if (requestDTO.getFields() != null) { + + TbTptFollowUpListDTO fields = requestDTO.getFields(); + + tbTptFollowUp.setRegimenType(fields.getRegimenType()); + + if (fields.getTreatmentStartDate() != null + && !fields.getTreatmentStartDate().isEmpty()) { + + tbTptFollowUp.setTreatmentStartDate( + Timestamp.valueOf(fields.getTreatmentStartDate()) + ); + } + + if (fields.getExpectedTreatmentCompletionDate() != null + && !fields.getExpectedTreatmentCompletionDate().isEmpty()) { + + tbTptFollowUp.setExpectedTreatmentCompletionDate( + Timestamp.valueOf(fields.getExpectedTreatmentCompletionDate()) + ); + } + + if (fields.getFollowUpDate() != null + && !fields.getFollowUpDate().isEmpty()) { + + tbTptFollowUp.setFollowUpDate( + Timestamp.valueOf(fields.getFollowUpDate()) + ); + } + + tbTptFollowUp.setFollowUpMonth( + fields.getMonthlyFollowUp() + ); + + tbTptFollowUp.setAdherenceToMedicines( + fields.getMedicineAdherence() + ); + + tbTptFollowUp.setAnyDiscomfort( + convertBollen(fields.getAnyDiscomfort()) + ); + + tbTptFollowUp.setTreatmentCompleted( + convertBollen(fields.getTreatmentCompleted()) + ); + + if (fields.getActualCompletionDate() != null + && !fields.getActualCompletionDate().isEmpty()) { + + tbTptFollowUp.setActualTreatmentCompletionDate( + Timestamp.valueOf(fields.getActualCompletionDate()) + ); + } + + tbTptFollowUp.setTptOutcome( + fields.getTptOutcome() + ); + + if ("Death".equalsIgnoreCase(fields.getTptOutcome())) { + + if (fields.getDateOfDeath() != null + && !fields.getDateOfDeath().isEmpty()) { + + tbTptFollowUp.setDateOfDeath( + Timestamp.valueOf(fields.getDateOfDeath()) + ); + } + + tbTptFollowUp.setPlaceOfDeath( + fields.getPlaceOfDeath() + ); + + tbTptFollowUp.setReasonForDeath( + fields.getReasonForDeath() + ); + } + } + + tbTptFollowUpRepo.save(tbTptFollowUp); + + createTptIncentiveIfEligible(tbTptFollowUp); + } + + response.setResponse("TPT follow up saved successfully"); + + } catch (Exception e) { + + response.setError(500, e.getMessage()); + return response.toString(); + } + + return response.toString(); + } + + + private static final Map MIN_FOLLOW_UPS = Map.of( + "1HP", 1, + "3HP", 3, + "3RH", 3, + "4R", 4, + "6H", 6, + "6LFX", 6 + ); + + + private void createTptIncentiveIfEligible(TbTptFollowUp saved) { + + // 1. Basic conditions + if (!Boolean.TRUE.equals(saved.getTreatmentCompleted()) + || saved.getActualTreatmentCompletionDate() == null + || saved.getRegimenType() == null + || saved.getTreatmentStartDate() == null + || saved.getBenId() == null) { + return; + } + + // 2. Regimen ka minimum follow-up count + Integer minRequired = MIN_FOLLOW_UPS.get(saved.getRegimenType().trim().toUpperCase()); + if (minRequired == null) { + return; // unknown regimen + } + + List cycleRows = tbTptFollowUpRepo + .findByBenIdAndRegimenTypeAndTreatmentStartDate( + saved.getBenId(), + saved.getRegimenType(), + saved.getTreatmentStartDate()); + + long completedMonths = cycleRows.stream() + .map(TbTptFollowUp::getFollowUpMonth) + .filter(Objects::nonNull) + .map(String::trim) + .distinct() + .count(); + + if (completedMonths < minRequired) { + return; + } + Timestamp completionDate = saved.getActualTreatmentCompletionDate(); + + incentiveLogic.incentiveForTbPreventiveFollowUp( + saved.getBenId(), + completionDate, + completionDate, + saved.getUserId()); + } + + @Override + public String getTptFollowUp(String token) { + + OutputResponse response = new OutputResponse(); + + try { + + if (token == null || token.trim().isEmpty()) { + response.setError(400, "Token is required"); + return response.toString(); + } + + Integer userId = jwtUtil.extractUserId(token); + + List tptFollowUps = + tbTptFollowUpRepo.findByUserId(userId); + + List tptFollowUpDTOs = + new ArrayList<>(); + + DateTimeFormatter formatter = + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + for (TbTptFollowUp tptFollowUp : tptFollowUps) { + + TbTptFollowUpDTO dto = new TbTptFollowUpDTO(); + + dto.setBenId(tptFollowUp.getBenId()); + dto.setUserId(tptFollowUp.getUserId()); + + TbTptFollowUpListDTO fields = + new TbTptFollowUpListDTO(); + + // Regimen Type + fields.setRegimenType( + tptFollowUp.getRegimenType() + ); + + // Treatment Start Date + if (tptFollowUp.getTreatmentStartDate() != null) { + fields.setTreatmentStartDate( + tptFollowUp.getTreatmentStartDate() + .toLocalDateTime() + .format(formatter) + ); + } + + // Expected Treatment Completion Date + if (tptFollowUp.getExpectedTreatmentCompletionDate() != null) { + fields.setExpectedTreatmentCompletionDate( + tptFollowUp.getExpectedTreatmentCompletionDate() + .toLocalDateTime() + .format(formatter) + ); + } + + // Follow Up Date + if (tptFollowUp.getFollowUpDate() != null) { + fields.setFollowUpDate( + tptFollowUp.getFollowUpDate() + .toLocalDateTime() + .format(formatter) + ); + } + + // Monthly Follow Up + fields.setMonthlyFollowUp( + tptFollowUp.getFollowUpMonth() + ); + + // Medicine Adherence + fields.setMedicineAdherence( + tptFollowUp.getAdherenceToMedicines() + ); + + // Any Discomfort + fields.setAnyDiscomfort( + convert(tptFollowUp.getAnyDiscomfort()) + ); + + // Treatment Completed + fields.setTreatmentCompleted( + convert(tptFollowUp.getTreatmentCompleted()) + ); + + // Actual Completion Date + if (tptFollowUp.getActualTreatmentCompletionDate() != null) { + fields.setActualCompletionDate( + tptFollowUp.getActualTreatmentCompletionDate() + .toLocalDateTime() + .format(formatter) + ); + } + + // TPT Outcome + fields.setTptOutcome( + tptFollowUp.getTptOutcome() + ); + + // Date of Death + if (tptFollowUp.getDateOfDeath() != null) { + fields.setDateOfDeath( + tptFollowUp.getDateOfDeath() + .toLocalDateTime() + .format(formatter) + ); + } + + // Place of Death + fields.setPlaceOfDeath( + tptFollowUp.getPlaceOfDeath() + ); + + // Reason for Death + fields.setReasonForDeath( + tptFollowUp.getReasonForDeath() + ); + + dto.setFields(fields); + + tptFollowUpDTOs.add(dto); + } + + ObjectMapper objectMapper = new ObjectMapper(); + + response.setResponse( + objectMapper.writeValueAsString(tptFollowUpDTOs) + ); + + } catch (Exception e) { + + e.printStackTrace(); + + response.setError( + 500, + "Failed to fetch TPT follow-up: " + e.getMessage() + ); + } + + return response.toString(); + } + + private Gson confirmedGson() { return new GsonBuilder() .registerTypeAdapter(LocalDate.class, new LocalDateAdapter()) @@ -271,4 +734,32 @@ private TBConfirmedCaseDTO toDTO(TBConfirmedCase entity) { return dto; } + + private String joinSideEffects(List sideEffects) { + return sideEffects.stream() + .filter(s -> s != null && !s.isBlank()) + .map(String::trim) + .collect(Collectors.joining(",")); + } + + private List splitSideEffects(String sideEffects) { + if (sideEffects == null) return new ArrayList<>(); + return Arrays.stream(sideEffects.split(",")) + .map(String::trim) + .filter(s -> !s.isEmpty()) + .collect(Collectors.toList()); + } + + private String convert(Boolean value) { + if (value == null) return null; + return value ? "Yes" : "No"; + } + + private Boolean convertBollen(String value) { + if (value != null && !value.isEmpty()) { + return value.equalsIgnoreCase("Yes"); + } else { + return false; + } + } }