package org.openlmis.vaccine.upload;
import lombok.NoArgsConstructor;
import org.openlmis.core.domain.*;
import org.openlmis.vaccine.dto.FacilityProgramProductISADTO;
import org.openlmis.core.repository.*;
import org.openlmis.core.upload.AbstractModelPersistenceHandler;
import org.openlmis.demographics.domain.EstimateCategory;
import org.openlmis.demographics.repository.EstimateCategoryRepository;
import org.openlmis.demographics.service.PopulationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
@NoArgsConstructor
public class FacilityProgramProductISAHandler extends AbstractModelPersistenceHandler {
@Autowired
FacilityProgramProductRepository repository;
@Autowired
FacilityRepository facilityRepository;
@Autowired
ProgramProductRepository programProductRepository;
@Autowired
ProgramRepository programRepository;
@Autowired
SupervisoryNodeRepository supervisoryNodeRepository;
@Autowired
RequisitionGroupRepository requisitionGroupRepository;
@Autowired
RequisitionGroupMemberRepository requisitionGroupMemberRepository;
@Autowired
PopulationService populationService;
@Autowired
EstimateCategoryRepository estimateCategoryRepository;
@Override
protected BaseModel getExisting(BaseModel record) {
FacilityProgramProductISADTO fppISA = (FacilityProgramProductISADTO)record;
return repository.getByCodes(fppISA.getFacility().getCode(), fppISA.getProgram().getCode(), fppISA.getProduct().getCode());
}
@Override
protected void save(BaseModel record) {
FacilityProgramProductISADTO fppISA = (FacilityProgramProductISADTO)record;
Facility facility = facilityRepository.getByCode(fppISA.getFacility().getCode());
ProgramProduct pp = programProductRepository.getByProgramAndProductCode(new ProgramProduct(fppISA.getProgram(),
fppISA.getProduct(), null, null));
Program program = programRepository.getByCode(fppISA.getProgram().getCode());
EstimateCategory category = estimateCategoryRepository.getByName(fppISA.getPopulationSourceName());
Long populationSourceId = (category != null) ? category.getId() : null;
Double wastageFactor = fppISA.getWastageFactor();
if (wastageFactor == -1.0) {
wastageFactor = repository.getOverriddenIsa(pp.getId(), facility.getId()).getWastageFactor();
}
ISA isa = new ISA();
isa.setWhoRatio(fppISA.getWhoRatio());
isa.setDosesPerYear(fppISA.getDosesPerYear());
isa.setWastageFactor(wastageFactor);
isa.setBufferPercentage(fppISA.getBufferPercentage());
isa.setMinimumValue(fppISA.getMinimumValue());
isa.setMaximumValue(fppISA.getMaximumValue());
isa.setAdjustmentValue(fppISA.getAdjustmentValue());
isa.setPopulationSource(populationSourceId);
saveFacilityProgramProductWithISA(facility, pp, isa);
// This method only really applies for VIMS, but is in place for all
saveWastageFactorForSupervisingFacilities(facility, pp, program, populationSourceId);
}
@Override
public String getMessageKey() {
return "error.duplicate.facility.program.product.isa";
}
private void saveWastageFactorForSupervisingFacilities(Facility facility, ProgramProduct pp, Program program,
Long populationSourceId) {
// Get all parent facilities of this facility
SupervisoryNode node = supervisoryNodeRepository.getFor(facility, program);
List<SupervisoryNode> parentNodes = supervisoryNodeRepository.getAllParentSupervisoryNodesInHierarchy(node);
for (SupervisoryNode parentNode : parentNodes) {
Double wastageFactor = 0.0;
// Re-calculate wastage factor if parent facility is a DVS/RVS/CVS (VIMS-specific)
Facility parentFacility = parentNode.getFacility();
if (parentFacility.getFacilityType().getCode().equalsIgnoreCase("cvs") ||
parentFacility.getFacilityType().getCode().equalsIgnoreCase("rvs") ||
parentFacility.getFacilityType().getCode().equalsIgnoreCase("dvs")) {
int totalPopulation = 0;
Double totalWeightedWastageFactor = 0.0;
// Do the calculation by looking at all children
// First, get all child facilities by looking at all requisition groups and their members
// NOTE: assumption here is that a supervisory node only has one requisition group assigned to it, which is true for VIMS
List<SupervisoryNode> childNodes = supervisoryNodeRepository.getAllChildSupervisoryNodesInHierarchy(parentNode);
List<RequisitionGroup> requisitionGroups = requisitionGroupRepository.getRequisitionGroups(childNodes);
List<RequisitionGroupMember> requisitionGroupMembers = new ArrayList<>();
for (RequisitionGroup requisitionGroup : requisitionGroups) {
requisitionGroupMembers.addAll(requisitionGroupMemberRepository.getMembersBy(requisitionGroup.getId()));
}
// For each requisition group member, check if facility is an SDP and add its wastage factor to running total
for (RequisitionGroupMember requisitionGroupMember : requisitionGroupMembers) {
// This call to the database is necessary, as facility does not have SDP info
// For VIMS, SDPs are defined as having facility type code "heac" (health facility) or "disp" (dispensary)
Facility childFacility = facilityRepository.getById(requisitionGroupMember.getFacility().getId());
if (childFacility.getFacilityType().getCode().equalsIgnoreCase("heac") ||
childFacility.getFacilityType().getCode().equalsIgnoreCase("disp")) {
ISA facilityISA = repository.getOverriddenIsa(pp.getId(), childFacility.getId());
if (facilityISA != null) {
Long population = populationService.getPopulation(childFacility, program, populationSourceId);
totalPopulation += population;
totalWeightedWastageFactor += population * facilityISA.getWastageFactor();
}
}
}
// Calculate average wastage factor
if (totalPopulation > 0) {
wastageFactor = totalWeightedWastageFactor / totalPopulation;
}
ISA isa = new ISA();
isa.setWhoRatio(0.0);
isa.setDosesPerYear(0);
isa.setWastageFactor(wastageFactor);
isa.setBufferPercentage(0.0);
isa.setAdjustmentValue(0);
isa.setPopulationSource(populationSourceId);
saveFacilityProgramProductWithISA(parentFacility, pp, isa);
}
}
}
private void saveFacilityProgramProductWithISA(Facility facility, ProgramProduct pp, ISA isa) {
ProgramProductISA ppISA = new ProgramProductISA(pp.getId(), isa);
FacilityProgramProduct fpp = new FacilityProgramProduct();
fpp.setFacilityId(facility.getId());
fpp.setId(pp.getId());
fpp.setProgramProductIsa(ppISA);
fpp.setOverriddenIsa(isa); // Not necessary, but done to get test case shouldSaveFacilityProgramProductISAAndCalculateParents() to work
repository.save(fpp);
}
}