Summary Table
Categories |
Total Count |
PII |
0 |
URL |
0 |
DNS |
0 |
EKL |
0 |
IP |
0 |
PORT |
0 |
VsID |
0 |
CF |
0 |
AI |
0 |
VPD |
0 |
PL |
0 |
Other |
0 |
File Content
/*
* SeocServiceImpl.java
* Copyright (c) 2017 Veterans Affairs.
*/
package gov.va.oneconsult.seoc.api.service.impl;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.transaction.Transactional;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import gov.va.oneconsult.seoc.api.exceptions.BusinessException;
import gov.va.oneconsult.seoc.api.exceptions.SeocEffectiveDateNotValidException;
import gov.va.oneconsult.seoc.api.json.CreateBillingCodeRequest;
import gov.va.oneconsult.seoc.api.json.CreateServiceRequest;
import gov.va.oneconsult.seoc.api.json.SeocActivateRequest;
import gov.va.oneconsult.seoc.api.json.SeocCreateRequest;
import gov.va.oneconsult.seoc.api.json.SeocCreateResponse;
import gov.va.oneconsult.seoc.api.json.SeocGenericResponse;
import gov.va.oneconsult.seoc.api.model.BillingCode;
import gov.va.oneconsult.seoc.api.model.CategoryOfCare;
import gov.va.oneconsult.seoc.api.model.ClinicalService;
import gov.va.oneconsult.seoc.api.model.Hptc;
import gov.va.oneconsult.seoc.api.model.PayableService;
import gov.va.oneconsult.seoc.api.model.Qasp;
import gov.va.oneconsult.seoc.api.model.Seoc;
import gov.va.oneconsult.seoc.api.model.ServiceHptc;
import gov.va.oneconsult.seoc.api.model.ServiceLine;
import gov.va.oneconsult.seoc.api.repository.PayableServiceRepository;
import gov.va.oneconsult.seoc.api.repository.SeocRepository;
import gov.va.oneconsult.seoc.api.repository.ServiceHptcRepository;
import gov.va.oneconsult.seoc.api.service.GenericService;
import gov.va.oneconsult.seoc.api.service.SeocService;
import gov.va.oneconsult.seoc.api.threadlocal.Context;
import gov.va.oneconsult.seoc.api.threadlocal.SeocThreadLocal;
import gov.va.oneconsult.seoc.api.util.ApiUtil;
import gov.va.oneconsult.seoc.api.util.Constants;
import gov.va.oneconsult.seoc.api.util.EncodeLoggerFactory;
/**
* Description: Implementation of CRUD operations on SEOC entity
*
* @author AbleVets
*/
@Transactional
@Component
public class SeocServiceImpl implements SeocService
{
public static final Logger logger = EncodeLoggerFactory.getLogger(SeocServiceImpl.class);
/**
* SeocRepository variable {@link SeocRepository}
*/
@Autowired
public SeocRepository seocRepository;
@Autowired
public PayableServiceRepository serviceRepository;
@Autowired
public GenericService genericService;
@Autowired
public ServiceHptcRepository serviceHptcRepository;
/**
* Description: Save Seoc
*
* @param seoc
* @return - Returns saved seoc object
*/
private Seoc save(final Seoc seoc)
{
Seoc retSeoc = seocRepository.save(seoc);
logger.info("Saving Seoc " + seoc.getId());
return retSeoc;
}
/**
* Description: Delete Seoc
*
* @param seoc
*/
private String delete(final Seoc seoc)
{
if (!seoc.getCalculatedStatus().equals(Constants.STATUS_INPROGRESS))
{
String message = "Seoc with status " + seoc.getCalculatedStatus()
+ " cannot be deleted";
return message;
}
seocRepository.delete(seoc);
logger.info("Deleted Seoc " + seoc.getId());
return null;
}
/**
* Description:
*
* @return int
*/
private int getMaxSeocKey()
{
Optional<Integer> maxSeocKeyValue = seocRepository.findMaxSeocKey();
int maxSeocKey = 0;
if (maxSeocKeyValue.isPresent())
{
maxSeocKey = maxSeocKeyValue.get();
}
return maxSeocKey;
}
/**
* Description: Find Seocs with the CategoryOfCare description cocDesc and have at least on published SEOC.
*
* @param cocDesc
* @return int
*/
private int getCountOfPublishedSeocsForCategoryOfCare(String cocDesc)
{
int[] seocKeys = seocRepository.findSeocsPublishedWithCategoryOfCare(cocDesc);
if(seocKeys==null) {
return 0;
}else {
return seocKeys.length;
}
}
/**
* Description: Retrieve previous Seoc of a pending revision Seoc from which the
* current seoc had been created
*
* @param seocKey
* @return Seoc
*/
private Seoc getPreviousSeocForPendingRevision(int seocKey)
{
Set<Seoc> previousSeocs = seocRepository.findBySeocKey(seocKey);
if (previousSeocs == null || previousSeocs.isEmpty())
{
logger.info("Unexpected condition. No Previous seocs for Seoc Key " + seocKey);
return null;
}
//Find all active seocs with same seoc key. It should be only active seoc available at a given time.
//get recent activatedseoc from the list by using version number
Seoc activeSeoc = null;
int versionPart3 = 0;
for (Seoc s : previousSeocs)
{
String calculatedStatus = s.getCalculatedStatus();
if (calculatedStatus.equalsIgnoreCase(Constants.STATUS_ACTIVE))
{
String[] versionNumberParts = SeocServiceHelper
.getPartsOfVersion(s.getVersionNumber());
if (versionNumberParts == null || versionNumberParts.length != 3)
{
continue;
}
int versionPart3Now = Integer.parseInt(versionNumberParts[2]);
if (versionPart3 < versionPart3Now)
{
versionPart3 = versionPart3Now;
activeSeoc = s;
}
}
}
return activeSeoc;
}
/**
* Description: Retrieve previous Seoc for a given seocId
*
* @param seocKey
* @param seocId
* @return Seoc
*/
private Seoc getPreviousSeoc(int seocKey, int id)
{
Seoc foundSeoc = getSeocById(id);
if (foundSeoc == null)
{
logger.error("Seoc not available with id " + id);
return null;
}
Set<Seoc> previousSeocs = seocRepository.findBySeocKey(seocKey);
if (previousSeocs == null || previousSeocs.isEmpty())
{
logger.info("Unexpected condition. No Previous seocs for Seoc Key " + seocKey);
return null;
}
Seoc previousSeoc = null;
String[] currentVersionParts = SeocServiceHelper.getPartsOfVersion(foundSeoc.getVersionNumber());
int currentVersionPart3 = currentVersionParts == null ? 0 : Integer.parseInt(currentVersionParts[2]);
int versionPart3 = 0;
for (Seoc s : previousSeocs)
{
String versionNumber = s.getVersionNumber();
if (versionNumber != null && versionNumber.contains(".")) {
String[] versionNumberParts = SeocServiceHelper.getPartsOfVersion(versionNumber);
if (versionNumberParts == null || versionNumberParts.length != 3) {
continue;
}
int versionPart3Now = Integer.parseInt(versionNumberParts[2]);
if (versionPart3 < versionPart3Now && (currentVersionPart3 == 0 || versionPart3Now < currentVersionPart3)) {
versionPart3 = versionPart3Now;
previousSeoc = s;
}
} else {
continue;
}
}
return previousSeoc;
}
/**
* Description: Check if the etag value in the thread local context is same as the stored Seoc hashValue
* @param foundSeoc
* @return boolean
*/
private boolean isEtagMatching(Seoc foundSeoc) throws BusinessException
{
Context context = SeocThreadLocal.getContext();
String hashValueIncoming = null;
String hashValueDbSeoc = null;
try {
hashValueIncoming = SeocServiceHelper.unpadEtag(context.getEtag());
hashValueDbSeoc = SeocServiceHelper.unpadEtag(
SeocServiceHelper.getHashCodeOfSeoc(foundSeoc));
logger.info("hashValueIncoming before activate "+ hashValueIncoming + " hashValueDbSeoc " + hashValueDbSeoc);
}
catch (BusinessException e) {
logger.error("Exception occured in isEtagMatching : " + e.getLocalizedMessage());
throw new BusinessException("Exception occured in isEtagMatching : " + e.getLocalizedMessage());
}
if (!hashValueIncoming.equals(hashValueDbSeoc))
{
return false;
}
return true;
}
/**
* Description: Reset etag value in the Context of Thread Local
* @param hashValue
*/
private void resetContextEtag(String hashValue)
{
logger.info("hashValueDbSeoc after completing the operation " + hashValue);
SeocThreadLocal.getContext().setEtag(hashValue);
}
/**
* Description: Retrieve user id from the context
* @return String
*/
private String getUserIdFromContext()
{
Context context = SeocThreadLocal.getContext();
String userId = context.getUserId();
return userId;
}
/**
* Description: Retrieve ServiceHptcs associated with the madicarecode of the cliniacl service of each service.
*
* @return Map<String, Set<ServiceHptc>>
*/
private Map<String, Set<ServiceHptc>> getServiceHptcs()
{
Set<ServiceHptc> allServiceHptcs = serviceHptcRepository.findAll();
Map<String, Set<ServiceHptc>> mapByMedicareCode = new HashMap<String, Set<ServiceHptc>>();
allServiceHptcs.forEach(sh-> {
Set<ServiceHptc> hptcs = mapByMedicareCode.get(sh.getMedicarecode());
if(hptcs==null || hptcs.isEmpty()) {
hptcs = new HashSet<ServiceHptc>();
mapByMedicareCode.put(sh.getMedicarecode(), hptcs);
}
hptcs.add(sh);
});
return mapByMedicareCode;
}
/**
* Description: Reverse given Date Hold SEOC back to In-Progress
* @param s - SEOC object which needs to be reverted to In-Progress
* @return SEOC
*/
private Seoc reverseDateHoldSeoc(Seoc s)
{
if (s == null) {
return s;
}
Seoc previousSeoc = getPreviousSeoc(s.getSeocKey(), s.getId());
s.setStatus(genericService.getStatusByDescription(Constants.STATUS_INPROGRESS));
s.setVersionNumber(null);
s.setEffectiveDate(null);
s.setActivatedTimestamp(null);
s.setActivatedBy(null);
if (previousSeoc != null) {
s.setVersionNumber(Constants.VERSION_PENDING_REVISION);
if (previousSeoc.getCalculatedStatus().equalsIgnoreCase(Constants.STATUS_ACTIVE)) {
previousSeoc.setEndDate(null);
previousSeoc.setDiscontinuedTimestamp(null);
previousSeoc.setDiscontinuedBy(null);
save(previousSeoc);
}
}
return s;
}
/**
* {@inheritDoc}
*/
@Override
public Seoc getSeocPendingRevision(Seoc s, Boolean noDeactivatedBillingCodes)
{
if (s == null) {
return s;
}
Seoc clonedSeoc = s.deepClone(noDeactivatedBillingCodes);
clonedSeoc.setVersionNumber(Constants.VERSION_PENDING_REVISION);
clonedSeoc.setActivatedBy(null);
clonedSeoc.setActivatedTimestamp(null);
clonedSeoc.setDiscontinuedBy(null);
clonedSeoc.setDiscontinuedTimestamp(null);
clonedSeoc.setEffectiveDate(null);
clonedSeoc.setEndDate(null);
clonedSeoc.setStatus(genericService.getStatusByDescription(Constants.STATUS_INPROGRESS));
return clonedSeoc;
}
/**
* {@inheritDoc}
*/
@Override
public Seoc getSeocPendingRevision(Seoc s)
{
return getSeocPendingRevision(s, false);
}
/**
* {@inheritDoc}
*/
@Override
public Set<Seoc> getAllSeocs()
{
return seocRepository.findAllSeocs();
}
/**
* {@inheritDoc}
*/
@Override
public List<Seoc> getActiveSeocs()
{
Set<Seoc> allActiveSeocs = seocRepository.findActiveSeocs();
if (allActiveSeocs != null && !allActiveSeocs.isEmpty())
{
Set<Seoc> activeSeocs = allActiveSeocs.stream()
.filter(s -> Constants.STATUS_ACTIVE.equalsIgnoreCase(s.getCalculatedStatus()))
.collect(Collectors.toSet());
List<Seoc> activeSeocsList = SeocServiceHelper.sortBySeocKeyEffectiveDate(activeSeocs);
return activeSeocsList;
} else
{
return new ArrayList<Seoc>();
}
}
/**
* {@inheritDoc}
*/
@Override
public List<Seoc> getPublishedSeocs()
{
Set<Seoc> allPubSeocs = seocRepository.findPublishedSeocs();
Map<String, Set<ServiceHptc>> mapByMedicareCode = getServiceHptcs();
if (allPubSeocs != null && !allPubSeocs.isEmpty())
{
allPubSeocs.forEach(s ->
{
List<PayableService> payableServices = s.getServices();
if (payableServices != null)
{
payableServices.forEach(service ->
{
Set<String> mscs = ApiUtil
.getMscFromClinicalServices(service.getClinicalServices());
if (mscs == null || mscs.isEmpty())
{
logger.error(
"Medicare Speciality Code not found for clinical services ");
} else
{
Stream<ServiceHptc> serviceHptcs = mapByMedicareCode.entrySet().stream().filter(m -> mscs.contains(m.getKey())).flatMap(ms -> ms.getValue().stream());
Set<String> values = serviceHptcs.map(hs -> hs.getHptc()).sorted().collect(Collectors.toSet());
service.setServiceHptcs(values);
}
});
}
});
return (SeocServiceHelper.sortBySeocKeyEffectiveDate(allPubSeocs));
} else
{
return new ArrayList<Seoc>();
}
}
/**
* {@inheritDoc}
*/
@Override
public Seoc getSeocById(int id)
{
Seoc foundSeoc = seocRepository.findById(id);
return foundSeoc;
}
/**
* {@inheritDoc}
*/
@Override
public Set<Seoc> getSeocByName(String name)
{
Set<Seoc> foundSeoc = seocRepository.findByName(name);
return foundSeoc;
}
/**
* {@inheritDoc}
*/
@Override
public Set<Seoc> getSeocNameWithDuplicates(String name)
{
Set<Seoc> foundDupSeoc = seocRepository.findDuplicateSeocNames(name);
return foundDupSeoc;
}
/**
* {@inheritDoc}
*/
@Override
public Set<Seoc> getByNameMatch(String name)
{
Set<Seoc> seocsFound = seocRepository.findSeocByNameMatch(name);
return seocsFound;
}
/**
* {@inheritDoc}
*/
@Override
public Set<Seoc> getBySeocKey(int seocKey)
{
Set<Seoc> foundSeocs = seocRepository.findBySeocKey(seocKey);
return foundSeocs;
}
/**
* {@inheritDoc}
*/
@Override
public Boolean isSeocAvailable(int seocKey, String name)
{
logger.info("Finding Seoc with Name");
// When SeocKey is available in the request it is an existing Seoc we
// are loading
Set<Seoc> seocsWithSameName = getSeocNameWithDuplicates(name);
if (seocsWithSameName == null || seocsWithSameName.isEmpty())
{
logger.info(
"No Seoc exists with name. It is available for usage in create/edit of a Seoc.");
return true;
} else if (seocKey != 0)
{
boolean seocNameNotValid = seocsWithSameName.stream()
.anyMatch(s -> s.getName().equalsIgnoreCase(name) && s.getSeocKey() != seocKey);
if (seocNameNotValid)
{
logger.error(
"Another Seoc with a different SeocKey exists with the name. It is not available for editing.");
return false;
} else
{
logger.info(
"No Seoc exists with name. It is available for usage in create/edit of a seoc.");
return true;
}
} else
{
logger.error("Another Seocexists with the name. It is not available for editing.");
return false;
}
}
/**
* {@inheritDoc}
*/
@Override
public SeocCreateResponse saveSeoc(SeocCreateRequest seocReq)
{
SeocCreateResponse seocResponse = new SeocCreateResponse();
ServiceLine sl = null;
CategoryOfCare coc = null;
Qasp q = null;
// Check ServiceLine for the description passed from the request
if (seocReq.getServiceLine() != null && !seocReq.getServiceLine().isEmpty())
{
sl = genericService.getServiceLineByFullDescription(seocReq.getServiceLine());
}
if (sl == null)
{
logger.error("Description of ServiceLine from the request " + seocReq.getServiceLine()
+ " ServiceLine object not found ");
} else
{
Boolean slDiscontinued = sl.getDiscontinued();
if (slDiscontinued != null && slDiscontinued)
{
logger.error("Description of ServiceLine from the request " + seocReq.getServiceLine()
+ " ServiceLine object is discontinued");
seocResponse.setStatus(Constants.FAILURE);
seocResponse.setComments("The Service Line value " + sl.getDescription() + " has been discontinued. A valid Service Line must be selected.");
return seocResponse;
}
}
// Check CategoryOfCare for the description passed from the request
if (seocReq.getCategoryOfCare() != null && !seocReq.getCategoryOfCare().isEmpty())
{
coc = genericService.getCategoryOfCareByDescription(seocReq.getCategoryOfCare());
}
if (coc == null)
{
logger.error("Description of CategoryOfCare from the request "
+ seocReq.getCategoryOfCare() + " CategoryOfCare object not found.");
} else
{
Boolean cocDiscontinued = coc.getDiscontinued();
if (cocDiscontinued != null && cocDiscontinued)
{
coc = null;
}
}
// Check Qasp for the description passed from the request
if (seocReq.getQasp() != null && !seocReq.getQasp().isEmpty())
{
q = genericService.getQaspByDescription(seocReq.getQasp());
}
if (q == null)
{
logger.error("Description of Qasp from the request " + seocReq.getQasp()
+ " QASP object not found ");
} else
{
Boolean qDiscontinued = q.getDiscontinued();
if (qDiscontinued != null && qDiscontinued)
{
q = null;
}
}
Seoc seoc = new Seoc();
try {
seoc.setName(seocReq.getName());
seoc.setServiceLine(sl);
seoc.setStatus(genericService.getStatusByDescription(Constants.STATUS_INPROGRESS));
seoc.setCategoryOfCare(coc);
seoc.setQasp(q);
seoc.setMaxAllowableVisits(seocReq.getMaxVisits());
seoc.setDuration(seocReq.getDuration());
seoc.setRev(seocReq.getRev());
seoc.setDescription(seocReq.getDescription());
seoc.setProceduralOverview(seocReq.getProceduralOverview());
seoc.setDisclaimer(seocReq.getDisclaimer());
seoc.setServices(readServices(seoc, seocReq.getServiceList()));
seoc.setHptcs(readHptcs(seocReq.getHptcs()));
if (seocReq.getSeocId() > 0)
{
// Assumption : Id passed in the request, Seoc available for
// editing. Update
// Checking the ifMatch condition for update request before updating the
// database
if (!isEtagMatching(getSeocById(seocReq.getSeocId())))
{
seocResponse.setStatus(Constants.PRECONDITION_FAILED);
seocResponse.setComments("ETag values for request and response did not match.");
return seocResponse;
}
// Call Update in the DB
seoc.setSeocKey(seocReq.getSeocKey());
seoc.setId(seocReq.getSeocId());
logger.info("Updating existing seoc");
seoc = update(seoc);
seocResponse.setUniqueId(seoc.getId());
seocResponse.setName(seoc.getName());
seocResponse.setSeocKey(seoc.getSeocKey());
seocResponse.setStatus(Constants.UPDATED);
seocResponse.setAction(Constants.EVENT_ACTION_SAVE);
seocResponse.setComments(seocReq.getComments());
//Set updated hashvalue of the seoc in the context
try {
resetContextEtag(SeocServiceHelper.unpadEtag(
SeocServiceHelper.getHashCodeOfSeoc(seoc)));
}
catch (BusinessException e) {
logger.error("Error in generating Etag value." + e.getLocalizedMessage());
}
} else
{
// Create new Seoc
if (seocReq.getSeocKey() > 0)
{
// seocKey supplied by the user
logger.info("Using seocKey value supplied in the request to create the Seoc");
seoc.setSeocKey(seocReq.getSeocKey());
} else
{
// Manually generate SeocKey by getting the max seocKey value
int maxSeocKey = getMaxSeocKey();
logger.info("Max SeocKey value " + maxSeocKey);
seoc.setSeocKey(maxSeocKey + 1);
}
// Create new Seoc record
seoc = save(seoc);
seocResponse.setUniqueId(seoc.getId());
seocResponse.setName(seoc.getName());
seocResponse.setSeocKey(seoc.getSeocKey());
seocResponse.setStatus(Constants.CREATED);
seocResponse.setAction(Constants.EVENT_ACTION_SAVE);
seocResponse.setComments(seocReq.getComments());
//Set updated hash value of the seoc in the context
try {
resetContextEtag(SeocServiceHelper.unpadEtag(
SeocServiceHelper.getHashCodeOfSeoc(seoc)));
}
catch (BusinessException e) {
logger.error("Error in generating Etag value." + e.getLocalizedMessage());
}
}
}
catch (BusinessException e) {
logger.info("Exception occured in saveSeoc. "+ e.getLocalizedMessage());
seocResponse.setStatus(Constants.FAILURE);
return seocResponse;
}
return seocResponse;
}
/**
* Description: Retrieve Hptc object for the hptc codes provided in the request
*
* @param hptcs
* @return Set<Hptc>
*/
private Set<Hptc> readHptcs(Set<String> hptcs)
{
if (hptcs == null || hptcs.isEmpty())
{
logger.info("No Hptcs found in the request");
return new HashSet<Hptc>();
}
Set<Hptc> hptcSet = genericService.getHptcs(hptcs);
return hptcSet;
}
/**
* Description: Read the services request object and build payableService object
* with data coming from the request.
*
* @param parentSeoc - Seoc for which the services are being built
* @param servicesFromRequest - Service request objects
* @return - Set of payable services which can be used for updating the database
*/
public List<PayableService> readServices(Seoc parentSeoc,
List<CreateServiceRequest> servicesFromRequest)
{
List<PayableService> reqServices = new ArrayList<PayableService>();
if (servicesFromRequest == null || servicesFromRequest.isEmpty())
{
logger.info("No services coming from the request");
return reqServices;
}
for (CreateServiceRequest serviceReq : servicesFromRequest)
{
PayableService payableService = new PayableService();
payableService.setId(serviceReq.getId());
payableService.setSeoc(parentSeoc);
payableService.setDescription(serviceReq.getDescription());
payableService.setFrequency(serviceReq.getFrequency());
payableService.setFrequencyType(serviceReq.getFrequencyType());
payableService.setVisits(serviceReq.getVisits());
Set<ClinicalService> css = new HashSet<ClinicalService>();
// If clinicalService is available
if (serviceReq.getClinicalServices() != null
&& !serviceReq.getClinicalServices().isEmpty())
{
css = genericService.getActiveClinicalServices(serviceReq.getClinicalServices());
}
payableService.setClinicalServices(css);
SeocServiceHelper.codeRequiredBillingCodeValidation(serviceReq.getCodeRequired(),
serviceReq.getBillingCodes());
payableService.setCodeRequired(serviceReq.getCodeRequired());
Set<String> billingCodes = serviceReq.getBillingCodes();
if (billingCodes != null && !billingCodes.isEmpty())
{
Set<BillingCode> foundBillingCodes = genericService.getActiveBillingCodes(billingCodes);
if (foundBillingCodes != null)
{
// Add billing code to the service
payableService.setBillingCodes(foundBillingCodes);
} else
{
payableService.setBillingCodes(new HashSet<BillingCode>());
logger.error(
"Billing code not found in look up table for the billing code value");
}
} else
{
payableService.setBillingCodes(new HashSet<BillingCode>());
}
reqServices.add(payableService);
}
return reqServices;
}
/**
* Description:Update SEOC
*
* @param reqSeoc
* @return - Returns updated SEOC object
*/
public Seoc update(final Seoc reqSeoc)
{
Seoc foundSeoc = getSeocById(reqSeoc.getId());
foundSeoc.setName(reqSeoc.getName());
foundSeoc.setSeocKey(reqSeoc.getSeocKey());
foundSeoc.setStatus(reqSeoc.getStatus());
foundSeoc.setServiceLine(reqSeoc.getServiceLine());
foundSeoc.setCategoryOfCare(reqSeoc.getCategoryOfCare());
foundSeoc.setQasp(reqSeoc.getQasp());
foundSeoc.setCategoryOfCare(reqSeoc.getCategoryOfCare());
foundSeoc.setQasp(reqSeoc.getQasp());
foundSeoc.setMaxAllowableVisits(reqSeoc.getMaxAllowableVisits());
foundSeoc.setDuration(reqSeoc.getDuration());
foundSeoc.setRev(reqSeoc.getRev());
foundSeoc.setDescription(reqSeoc.getDescription());
foundSeoc.setProceduralOverview(reqSeoc.getProceduralOverview());
foundSeoc.setDisclaimer(reqSeoc.getDisclaimer());
// Syncup Services
SeocServiceHelper.syncServices(foundSeoc, reqSeoc);
//SyncUp Hptcs
SeocServiceHelper.syncHptcs(foundSeoc, reqSeoc);
// Update existing Seoc
Seoc retSeoc = save(foundSeoc);
return retSeoc;
}
/**
* {@inheritDoc}
*/
public SeocCreateResponse createPendingRevision(int seocId)
{
SeocCreateResponse seocResponse = new SeocCreateResponse();
Seoc thatSeoc = getSeocById(seocId);
logger.info("Started creating pending revision");
if (thatSeoc == null)
{
logger.error("Seoc not available with id " + seocId);
seocResponse.setStatus(Constants.FAILURE);
return seocResponse;
}
Seoc savedSeoc = null;
SeocGenericResponse validateResponse = validPendingRevision(seocId);
if (validateResponse.getStatus() != null
&& validateResponse.getStatus().equalsIgnoreCase(Constants.FAILURE))
{
seocResponse.setMessage(validateResponse.getMessage());
seocResponse.setStatus(Constants.FAILURE);
return seocResponse;
}
logger.info("Started creating a clone seoc object.");
// Deep clone the Seoc object
Seoc thisSeoc = getSeocPendingRevision(thatSeoc, true);
savedSeoc = save(thisSeoc);
logger.info("Successfully created a pending revision");
seocResponse.setUniqueId(savedSeoc.getId());
seocResponse.setSeocKey(savedSeoc.getSeocKey());
seocResponse.setName(savedSeoc.getName());
seocResponse.setAction(Constants.EVENT_ACTION_SAVE);
seocResponse.setStatus(Constants.CREATED);
return seocResponse;
}
/**
* {@inheritDoc}
*/
@Override
public SeocGenericResponse validPendingRevision(int seocId)
{
SeocGenericResponse seocResponse = new SeocGenericResponse();
Seoc foundSeoc = getSeocById(seocId);
if (foundSeoc == null)
{
logger.error("Seoc not available with id " + seocId);
seocResponse.setStatus(Constants.FAILURE);
return seocResponse;
}
String status = foundSeoc.getCalculatedStatus();
if (!status.equalsIgnoreCase(Constants.STATUS_ACTIVE)) {
String message = "Seoc is not eligible for Pending revision. Current status of SEOC is "
+ foundSeoc.getCalculatedStatus();
logger.error(message);
seocResponse.setMessage(message);
seocResponse.setStatus(Constants.FAILURE);
return seocResponse;
}
// Validation to check if the seoc is eligible for this operation just before
// creating a pending revision
Set<Seoc> seocsWithSameKey = getBySeocKey(foundSeoc.getSeocKey());
if (seocsWithSameKey != null && !seocsWithSameKey.isEmpty())
{
boolean revisionInMaking = seocsWithSameKey.stream()
.anyMatch(s -> (s.getVersionNumber() != null
&& s.getVersionNumber().equalsIgnoreCase(Constants.VERSION_PENDING_REVISION))
|| s.getCalculatedStatus().equalsIgnoreCase(Constants.STATUS_DATEHOLD));
if (revisionInMaking)
{
logger.info("Another Seoc with same seoc key " + foundSeoc.getSeocKey()
+ " is in progress ");
seocResponse.setMessage(
"Pending Revision Draft exists for another Seoc with same seoc key "
+ foundSeoc.getSeocKey());
seocResponse.setStatus(Constants.FAILURE);
} else
{
seocResponse.setMessage("Pending revision can be created.");
seocResponse.setStatus(Constants.SUCCESS);
}
} else
{
seocResponse.setMessage("Pending revision can be created.");
seocResponse.setStatus(Constants.SUCCESS);
}
return seocResponse;
}
/**
* {@inheritDoc}
*/
@Override
public SeocGenericResponse activateSeoc(SeocActivateRequest seocActivateRequest)
{
int seocId = seocActivateRequest.getSeocId();
String effectiveDateParam = seocActivateRequest.getEffectiveDate();
SeocGenericResponse seocResponse = new SeocGenericResponse();
Seoc foundSeoc = getSeocById(seocId);
logger.info("Activating SEOC with id " + seocId + " and effectiveDate " + effectiveDateParam);
//Seoc is considered active only when the effective date is not null and status is not DateHold
//DateHold with effectiveDate, Seoc has already been activated
//Inprogress without effective date, Seoc is ready for activation
//Not Inprogress with effectiveDate, not a valid condition, not valid for activation
if (foundSeoc == null || !foundSeoc.getCalculatedStatus().equalsIgnoreCase(Constants.STATUS_INPROGRESS))
{
seocResponse.setStatus(Constants.FAILURE);
seocResponse.setMessage(
"Seoc status not valid for activation.");
return seocResponse;
}
try {
if (!isEtagMatching(foundSeoc))
{
seocResponse.setStatus(Constants.PRECONDITION_FAILED);
seocResponse.setComments("ETag values for request and response did not match.");
return seocResponse;
}
}
catch (BusinessException e) {
seocResponse.setStatus(Constants.FAILURE);
seocResponse.setComments("Error in generating ETag value.");
return seocResponse;
}
Seoc previousSeoc = null;
String versionNumber = null;
String[] datePieces = effectiveDateParam.split("[-]");
Calendar calendar = new GregorianCalendar(Integer.parseInt(datePieces[2]), Integer.parseInt(datePieces[0]) - 1, Integer.parseInt(datePieces[1]));
Date effectiveDate = calendar.getTime();
logger.info("Validating effectiveDate " + effectiveDateParam);
if (ApiUtil.getUTCCalendarDate(effectiveDate).getTime() < new Date().getTime()) {
throw new SeocEffectiveDateNotValidException("Activation failed due to invalid effectiveDate.");
}
logger.info("Validating Seoc with Id " + seocId);
SeocGenericResponse validateResponse = validSeocActivate(seocId);
if ((validateResponse.getStatus() != null
&& validateResponse.getStatus().equalsIgnoreCase(Constants.FAILURE))
|| (validateResponse.getMessage()!=null && !validateResponse.getMessage().isEmpty()))
{
seocResponse.setStatus(Constants.FAILURE);
seocResponse.setMessage(validateResponse.getMessage());
return seocResponse;
}
// Activating a pending revision seoc - Find version number
if (foundSeoc != null) {
if (foundSeoc.getVersionNumber() != null
&& foundSeoc.getVersionNumber().equalsIgnoreCase(Constants.VERSION_PENDING_REVISION))
{
logger.info("Activating pending revision Seoc");
// Find the previous Seoc from which the current seoc has been created
previousSeoc = getPreviousSeocForPendingRevision(foundSeoc.getSeocKey());
if (previousSeoc == null)
{
logger.error("Error occured in finding the previous active seoc.");
seocResponse.setStatus(Constants.FAILURE);
seocResponse.setMessage("Error occured in finding the previous active seoc.");
return seocResponse;
}
// Finding the version number
/*
* "PENDING REVISION VERSION RULES: Version = ""A.B.C"" where 1. ""A"" is the
* same as the previous SEOC version 2. If CoC is unchanged, ""B"" is the same
* as the previous SEOC version ""C"" is one more than the value of the previous
* SEOC version 3. If CoC is changed, ""B"" is the number of active SEOCs with
* the new CoC ""C"" = 1"
*/
String prevSeocVersionNumber = previousSeoc.getVersionNumber();
String[] versionNumberParts = SeocServiceHelper
.getPartsOfVersion(prevSeocVersionNumber);
if (versionNumberParts == null || versionNumberParts.length != 3)
{
seocResponse.setStatus(Constants.FAILURE);
seocResponse.setMessage("Incorrect version number of previous active seoc.");
return seocResponse;
}
int a = Integer.parseInt(versionNumberParts[0]);
int b = 0;
int c = 1;
logger.info("Creating version number from previous seoc version number parts.");
logger.info("Previous SeocConfiguartionVersion :: " + a);
if (previousSeoc.getCategoryOfCare().getDescription()
.equalsIgnoreCase(foundSeoc.getCategoryOfCare().getDescription()))
{
logger.info("Previous Seoc Coc is same as pending revision Coc");
b = Integer.parseInt(versionNumberParts[1]);
} else
{
logger.info("Coc changed from previous Seoc to current Seoc");
b = this.getCountOfPublishedSeocsForCategoryOfCare(
foundSeoc.getCategoryOfCare().getDescription());
logger.info("Number of unique published Seocs available with CategoryOfCare "
+ foundSeoc.getCategoryOfCare().getDescription() + " :: " + b);
}
c = Integer.parseInt(versionNumberParts[2]) + 1;
versionNumber = "" + a + "." + b + "." + c;
} else// Activating a draft Seoc - Find version number
{
logger.info("Activating Draft Seoc");
/*
* Version Number Rules for draft Seoc Activation Version = ""A.B.C"" where 1.
* ""A"" = currProgramVersion in SeocConfig table 2. ""B"" is the number of
* active SEOCs with the same CoC. 3. ""C"" = 1"
*/
logger.info("Evaluating the next available version number..");
int a = genericService.getCurrentSeocConfigVersion();
int b = this
.getCountOfPublishedSeocsForCategoryOfCare(
foundSeoc.getCategoryOfCare().getDescription());
int c = 1;
logger.info("SeocConfiguartionVersion :: " + a);
logger.info("Number of unique published Seocs available with CategoryOfCare "
+ foundSeoc.getCategoryOfCare().getDescription() + " :: " + b);
versionNumber = "" + a + "." + b + "." + c;
}
}
logger.info("Version Number " + versionNumber);
/*
* Seoc is allowed for activation. Set ActivatedTimestamp, EffectiveDate,
* VersionNumber and Status
*/
logger.info("Preparing for Seoc activation, setting fields ActivatedTimestamp :" + effectiveDate
+ " Status : " + Constants.STATUS_ACTIVE + " EffectiveDate : " + effectiveDate
+ " CodedTimestamp for each service : " + effectiveDate + " versionNumber : "
+ versionNumber);
foundSeoc.setActivatedTimestamp(effectiveDate);
foundSeoc.setEffectiveDate(effectiveDate);
foundSeoc.setActivatedBy(getUserIdFromContext());
foundSeoc.getServices().forEach(s ->
{
s.setCodedTimestamp(effectiveDate);
});
foundSeoc.setVersionNumber(versionNumber);
foundSeoc.setStatus(genericService.getStatusByDescription(Constants.STATUS_DATEHOLD));
//Save the activated Seoc
//Update comment before activating the SEOC
foundSeoc.updateFormattedComment();
save(foundSeoc);
//Set updated hashvalue of the seoc in the context
try {
resetContextEtag(SeocServiceHelper.unpadEtag(
SeocServiceHelper.getHashCodeOfSeoc(foundSeoc)));
}
catch (BusinessException e) {
logger.error("Error in generating Etag value." + e.getLocalizedMessage());
}
if (previousSeoc != null)
{
logger.info("Discontinue previous Seoc and set end date to " + effectiveDate);
previousSeoc.setEndDate(effectiveDate);
previousSeoc.setDiscontinuedTimestamp(effectiveDate);
previousSeoc.setDiscontinuedBy(getUserIdFromContext());
save(previousSeoc);
}
logger.info("Successfully activated Seoc");
seocResponse.setSeocId(foundSeoc.getId());
seocResponse.setSeocKey(foundSeoc.getSeocKey());
seocResponse.setStatus(Constants.SUCCESS);
return seocResponse;
}
/**
* {@inheritDoc}
*/
@Override
public SeocGenericResponse validSeocActivate(int seocId)
{
SeocGenericResponse seocResponse = new SeocGenericResponse();
Seoc foundSeoc = getSeocById(seocId);
logger.info("Checking if the seoc is valid for Activation ");
if (foundSeoc == null)
{
logger.error("No Seoc available with id " + seocId);
seocResponse.setStatus(Constants.FAILURE);
seocResponse.setMessage("No Seoc available with id " + seocId);
return seocResponse;
}
if (!foundSeoc.getCalculatedStatus().equalsIgnoreCase(Constants.STATUS_INPROGRESS))
{
logger.error("SEOC is not In-Progress. Not valid for activation " + seocId);
//Sending response status as SUCCESS instead of FAILURE. Reason:UI only understands SUCCESS status from this call.
seocResponse.setStatus(Constants.SUCCESS);
seocResponse.setMessage("SEOC is not In-Progress. Not valid for activation " + seocId);
return seocResponse;
}
logger.info("Running the validation rules");
// Validate the fields of SEOC
SeocServiceHelper.validateSeocForActivation(foundSeoc,
genericService.getStatusByDescription(Constants.STATUS_INPROGRESS),
genericService.getStatusByDescription(Constants.STATUS_DATEHOLD));
logger.info("Seoc is valid for activation");
seocResponse.setSeocId(foundSeoc.getId());
seocResponse.setStatus(Constants.SUCCESS);
return seocResponse;
}
/**
* {@inheritDoc}
*/
@Override
public SeocGenericResponse deleteSeoc(int seocId)
{
SeocGenericResponse seocResponse = new SeocGenericResponse();
Seoc foundSeoc = getSeocById(seocId);
logger.info("Validating Seoc for Deletion");
if (foundSeoc == null)
{
logger.error("Seoc not available with id " + seocId);
seocResponse.setMessage("Seoc not available with id " + seocId);
seocResponse.setStatus(Constants.FAILURE);
return seocResponse;
}
try {
if (!isEtagMatching(foundSeoc))
{
seocResponse.setStatus(Constants.PRECONDITION_FAILED);
seocResponse.setComments("ETag values for request and response did not match.");
return seocResponse;
}
}
catch (BusinessException e) {
seocResponse.setStatus(Constants.FAILURE);
seocResponse.setComments("Error occured in generating eTag.");
return seocResponse;
}
String message = delete(foundSeoc);
if (message != null && !message.isEmpty())
{
seocResponse.setStatus(Constants.FAILURE);
seocResponse.setMessage(message);
return seocResponse;
}
seocResponse.setStatus(Constants.SUCCESS);
seocResponse.setSeocId(foundSeoc.getId());
seocResponse.setSeocKey(foundSeoc.getSeocKey());
seocResponse.setMessage("Successfully deleted the seoc and associated payable services.");
return seocResponse;
}
/**
* ({@inheritDoc}
*/
@Override
public SeocGenericResponse discontinueSeoc(int seocId)
{
SeocGenericResponse seocResponse = new SeocGenericResponse();
Seoc foundSeoc = getSeocById(seocId);
if (foundSeoc == null)
{
logger.error("Seoc not available with id " + seocId);
seocResponse.setStatus(Constants.FAILURE);
seocResponse.setMessage("Seoc not available with id " + seocId);
return seocResponse;
}
logger.info("Found the Seoc to be discontinued");
String calculatedSeocStatus = foundSeoc.getCalculatedStatus();
if (!calculatedSeocStatus.equalsIgnoreCase(Constants.STATUS_ACTIVE))
{
logger.info("Seoc is not eligible for discontinuation. Current status of SEOC is "
+ calculatedSeocStatus);
seocResponse.setStatus(Constants.FAILURE);
seocResponse.setMessage(
"Seoc is not eligible for discontinuation. Current status of SEOC is "
+ calculatedSeocStatus);
return seocResponse;
}
// Find all seocs with same key
Set<Seoc> seocsWithSameKey = getBySeocKey(foundSeoc.getSeocKey());
// If a seoc with same key exists check if there is a seoc which is a pending
// revision
if (seocsWithSameKey != null && !seocsWithSameKey.isEmpty())
{
Optional<Seoc> revisionSeoc = seocsWithSameKey.stream()
.filter(s -> s.getVersionNumber() != null
&& s.getVersionNumber().equalsIgnoreCase(Constants.VERSION_PENDING_REVISION))
.findAny();
// If a pending revision exists. Delete that seoc
if (revisionSeoc.isPresent())
{
logger.info("A Seoc with same key is Pending revision."
+ " Deleting the pending revision seoc before discontinuing the parent seoc.");
String deletedMessage = delete(revisionSeoc.get());
if (deletedMessage != null)
{
seocResponse.setSeocId(revisionSeoc.get().getId());
seocResponse.setStatus(Constants.FAILURE);
seocResponse.setMessage(deletedMessage);
return seocResponse;
}
logger.info(
"Successfully deleted pending revision seoc " + revisionSeoc.get().getId());
} else
{
logger.info("No pending revision available for seoc key " + foundSeoc.getSeocKey());
}
}
// Discontinue the Seoc
Date now = new Date();
foundSeoc.setEndDateToday();
foundSeoc.setDiscontinuedTimestamp(now);
foundSeoc.setDiscontinuedBy(getUserIdFromContext());
save(foundSeoc);
logger.info("Successfully discontinued the seoc");
seocResponse.setSeocId(foundSeoc.getId());
seocResponse.setSeocKey(foundSeoc.getSeocKey());
seocResponse.setStatus(Constants.SUCCESS);
return seocResponse;
}
/**
* ({@inheritDoc}
*/
public SeocGenericResponse reverseSeoc(int id) {
SeocGenericResponse seocResponse = new SeocGenericResponse();
Seoc foundSeoc = getSeocById(id);
logger.info("Validating Seoc for Reverse");
if (foundSeoc == null)
{
logger.error("Seoc not available with id " + id);
seocResponse.setMessage("Seoc not available with id " + id);
seocResponse.setStatus(Constants.FAILURE);
return seocResponse;
}
try {
if (!isEtagMatching(foundSeoc))
{
seocResponse.setStatus(Constants.PRECONDITION_FAILED);
seocResponse.setComments("ETag values for request and response did not match.");
return seocResponse;
}
}
catch (BusinessException e) {
seocResponse.setStatus(Constants.FAILURE);
seocResponse.setComments("Error in generating ETag value.");
return seocResponse;
}
String calculatedSeocStatus = foundSeoc.getCalculatedStatus();
if (!calculatedSeocStatus.equalsIgnoreCase(Constants.STATUS_DATEHOLD))
{
logger.info("Seoc is not eligible for reversal. Current status of SEOC is "
+ calculatedSeocStatus);
seocResponse.setStatus(Constants.FAILURE);
seocResponse.setMessage(
"Seoc is not eligible for reversal. Current status of SEOC is "
+ calculatedSeocStatus);
return seocResponse;
}
foundSeoc = reverseDateHoldSeoc(foundSeoc);
save(foundSeoc);
//Set updated hashvalue of the seoc in the context
try {
resetContextEtag(SeocServiceHelper.unpadEtag(
SeocServiceHelper.getHashCodeOfSeoc(foundSeoc)));
}
catch (BusinessException e) {
logger.error("Error in generating Etag value." + e.getLocalizedMessage());
}
logger.info("Successfully reversed the seoc");
seocResponse.setSeocId(foundSeoc.getId());
seocResponse.setSeocKey(foundSeoc.getSeocKey());
seocResponse.setStatus(Constants.SUCCESS);
return seocResponse;
}
/**
* {@inheritDoc}
*/
public Set<Seoc> retrieveSeocsByBillingCode(String code)
{
if(code==null) {
logger.debug("Billing code value not available.");
return null;
}
BillingCode billingCode = genericService.getActiveBillingCode(code);
// No Billing Code available in the DB
if (billingCode == null)
{
logger.debug("Billing code not found in the database.");
return null;
}
Set<PayableService> services = serviceRepository.findByBillingCodesId(billingCode.getId());
if (services == null)
{
logger.debug("Billing code was not used in any services.");
return null;
}
Integer[] serviceIds = services.stream().map(PayableService::getId)
.collect(Collectors.toList()).stream().toArray(Integer[]::new);
Set<Seoc> seocs = seocRepository.findByServicesIdIn(serviceIds);
if (seocs == null || seocs.isEmpty())
{
logger.debug("Seocs not retrieved for the services on queried billing code.");
return null;
}
Set<Seoc> availableSeocs = seocs.stream()
.filter(s -> (Constants.seocStatusToManageBillingCodes.contains(s.getCalculatedStatus())))
.collect(Collectors.toSet());
Map<Integer, List<Seoc>> seocsByKey =
availableSeocs.stream().collect(Collectors.groupingBy(Seoc::getSeocKey));
availableSeocs = new HashSet<Seoc>();
for (List<Seoc> s : seocsByKey.values())
{
if (s.size() > 1)
{
if (s.stream().anyMatch(seoc -> seoc.getCalculatedStatus()
.equalsIgnoreCase(Constants.STATUS_INPROGRESS)))
{
availableSeocs.add(s.stream()
.filter(seoc -> seoc.getCalculatedStatus()
.equalsIgnoreCase(Constants.STATUS_INPROGRESS))
.findAny().get());
} else
{
Optional<Seoc> dateHold = s.stream()
.filter(seoc -> seoc.getCalculatedStatus()
.equalsIgnoreCase(Constants.STATUS_DATEHOLD))
.findAny();
if (dateHold.isPresent())
{
availableSeocs.add(dateHold.get());
}
}
} else
{
availableSeocs.addAll(s);
}
}
return availableSeocs;
}
/**
* {@inheritDoc}
*/
@Override
public SeocGenericResponse createBillingCode(CreateBillingCodeRequest billingCodeRequest)
{
SeocGenericResponse response = new SeocGenericResponse();
BillingCode billingCode = new BillingCode();
String code = billingCodeRequest.getBillingCode();
if(code!=null) {
BillingCode foundBillingCode = genericService.getActiveBillingCode(code);
if(foundBillingCode!=null) {
response.setAction(Constants.FAILURE);
response.setComments("Billing code exists with same billingCode value.");
logger.info("Billing code exists with the same billing code data.");
return response;
}
}
billingCode.setBillingCode(billingCodeRequest.getBillingCode());
billingCode.setCodeType(billingCodeRequest.getCodeType());
billingCode.setDescription(billingCodeRequest.getDescription());
billingCode.setPrecertRequired(billingCodeRequest.getPrecertRequired());
billingCode = genericService.saveBillingCode(billingCode);
if(billingCode!=null) {
logger.info("Created new billing code.");
response.setAction(Constants.CREATED);
return response;
}
logger.info("Failed to created new billing code");
response.setAction(Constants.FAILURE);
response.setComments("Failed to created new billing code.");
return response;
}
/**
* {@inheritDoc}
*/
@Override
public SeocGenericResponse manageBillingCode(CreateBillingCodeRequest billingCodeRequest)
{
SeocGenericResponse seocResponse = new SeocGenericResponse();
String prevCode = null;
if(billingCodeRequest == null)
{
seocResponse.setAction(Constants.FAILURE);
seocResponse.setComments("Invalid Billing code request.");
logger.debug("Invalid Billing code request.");
return seocResponse;
}
if (billingCodeRequest.getPrevBillingCode()!=null)
{
prevCode = billingCodeRequest.getPrevBillingCode();
}
BillingCode prevBC = genericService.getActiveBillingCode(prevCode);
//No Billing Code available in the DB
if (prevBC == null)
{
seocResponse.setAction(Constants.FAILURE);
seocResponse.setComments("Billing code not found in the database.");
logger.debug("Billing code not found in the database.");
return seocResponse;
}
// Find availableSeocs with the given billing code
Set<Seoc> availableSeocs = retrieveSeocsByBillingCode(prevCode);
Map<Boolean, List<Seoc>> seocLists = null;
List<Seoc> inProgressSeocs = null;
List<Seoc> dateHoldSeocs = null;
List<Seoc> activeSeocs = null;
// Split the availableSeocs to three lists - Seocs with status In-progress, Active, or Date Hold
if (availableSeocs != null)
{
seocLists = availableSeocs
.stream()
.collect(Collectors.partitioningBy(s -> s.getCalculatedStatus().equalsIgnoreCase(Constants.STATUS_INPROGRESS)));
inProgressSeocs = seocLists.get(true);
activeSeocs = seocLists.get(false);
}
if (activeSeocs != null && !activeSeocs.isEmpty()) {
seocLists = activeSeocs
.stream()
.collect(Collectors.partitioningBy(s -> s.getCalculatedStatus().equalsIgnoreCase(Constants.STATUS_DATEHOLD)));
dateHoldSeocs = seocLists.get(true);
activeSeocs = seocLists.get(false);
}
if (billingCodeRequest.isDiscontinueRequest())
{
updateSeocsForDiscontinuedBillingCode(inProgressSeocs, activeSeocs, dateHoldSeocs, prevBC);
// Deactivate the Billing Code and save
prevBC.setDeactivated(true);
genericService.saveBillingCode(prevBC);
seocResponse.setAction(Constants.SUCCESS);
seocResponse.setComments("Discontinued Billing Code successfully.");
} else
{
//Deactivate and save previous billing code
prevBC.setDeactivated(true);
genericService.saveBillingCode(prevBC);
//Create cloned billing code object
BillingCode bc = prevBC.deepClone();
bc.setBillingCode(billingCodeRequest.getBillingCode());
bc.setCodeType(billingCodeRequest.getCodeType());
bc.setDescription(billingCodeRequest.getDescription());
bc.setPrecertRequired(billingCodeRequest.getPrecertRequired());
bc.setDeactivated(false);
//save new billing code
BillingCode newBC = genericService.saveBillingCode(bc);
updateSeocsForEditBillingCode(inProgressSeocs, activeSeocs, dateHoldSeocs, prevBC, newBC);
seocResponse.setAction(Constants.SUCCESS);
seocResponse.setComments("Edited Billing Code successfully.");
}
return seocResponse;
}
/**
* Description: Updates the SEOCs which are using the Billing Code
* 1. Revert Date Hold SEOCs to In-Progress and Delete Billing Code
* 2. Delete Billing Code from the In-Progress SEOCs
* 3. Create Pending Revision for Active SEOCs(delete billing code from pending revision)
* @param inProgressSeocs - SEOCs with status In-Progress
* @param activeSeocs - SEOCs with status active
* @param dateHoldSeocs - SEOCs with status Date Hold
* @param bc - Billing Code
*/
private void updateSeocsForDiscontinuedBillingCode(List<Seoc> inProgressSeocs, List<Seoc> activeSeocs, List<Seoc> dateHoldSeocs, BillingCode bc)
{
// Date Hold Seocs
if (dateHoldSeocs == null || dateHoldSeocs.isEmpty())
{
logger.debug("No Date Hold Seocs available.");
} else
{
// For each Date Hold Seoc
// 1. Revert the Seoc back to In-Progress
// 2. Remove the old billing code
// 3. Add new billing code
dateHoldSeocs.forEach(s ->
{
if (s != null)
{
//Revert Seoc back to In-Progress
s = reverseDateHoldSeoc(s);
//Remove Billing Code from the In-Progress Seoc
s.removeBillingCode(bc);
save(s);
}
});
}
// In-progress Seocs
if (inProgressSeocs == null || inProgressSeocs.isEmpty())
{
logger.debug("No In-Progress Seocs available.");
} else
{
// For each In-progress Seoc, remove the billing code
inProgressSeocs.forEach(s ->
{
if (s != null)
{
//Remove Billing Code from the In-Progress Seoc
s.removeBillingCode(bc);
save(s);
}
});
}
// Active Seocs
if (activeSeocs == null || activeSeocs.isEmpty())
{
logger.debug("No Active Seocs avialable");
} else
{
// For each Active Seoc,
// 1. Clone the Seoc and prepare to create Pending Revision
// 2. Remove BillingCode
// 3. Save the Seoc
activeSeocs.forEach(s ->
{
if (s != null)
{
// Create Pending Revision
Seoc clonedSeoc = getSeocPendingRevision(s);
clonedSeoc.removeBillingCode(bc);
save(clonedSeoc);
}
});
}
}
/**
* Description: Updates the SEOCs which are using the Billing Code
* 1. Date Hold SEOCs - Revert Date Hold SEOCs to In-Progress, remove previous billing code, and add new billing code
* 2. In-progress SEOCs - Remove previous billing code and add new billing code
* 3. Active/Date Hold - Create Pending Revision for SEOCs(update billing code in the pending revision)
* @param inProgressSeocs - SEOCs with status In-Progress
* @param activeSeocs - SEOCs with status Active or Date Hold
* @param prevBC - Previous Billing Code
* @param newBC - New Billing Code
*/
private void updateSeocsForEditBillingCode(List<Seoc> inProgressSeocs, List<Seoc> activeSeocs, List<Seoc> dateHoldSeocs, BillingCode prevBC, BillingCode newBC)
{
// Date Hold Seocs
if (dateHoldSeocs == null || dateHoldSeocs.isEmpty())
{
logger.debug("No Date Hold Seocs available.");
} else
{
// For each Date Hold Seoc
// 1. Revert the Seoc back to In-Progress
// 2. Remove the old billing code
// 3. Add new billing code
dateHoldSeocs.forEach(s ->
{
if (s != null)
{
//Revert Seoc back to In-Progress
s = reverseDateHoldSeoc(s);
//Update billing code in In-Progress Seoc
s.updateBillingCode(prevBC, newBC);
save(s);
}
});
}
// In-progress Seocs
if (inProgressSeocs == null || inProgressSeocs.isEmpty())
{
logger.debug("No In-Progress Seocs available.");
} else
{
// For each In-progress Seoc, remove the old billing code and add new billing code
inProgressSeocs.forEach(s ->
{
if (s != null)
{
//Update billing code in In-Progress Seoc
s.updateBillingCode(prevBC, newBC);
save(s);
}
});
}
// Active Seocs
if (activeSeocs == null || activeSeocs.isEmpty())
{
logger.debug("No Active Seocs avialable");
} else
{
// For each Active Seoc,
// 1. Clone the seoc and prepare to create Pending Revision
// 2. Remove BillingCode
// 3. Save the Seoc
activeSeocs.forEach(s ->
{
if (s != null)
{
// Create Pending Revision of Active Seoc
Seoc clonedSeoc = getSeocPendingRevision(s);
clonedSeoc.updateBillingCode(prevBC, newBC);
save(clonedSeoc);
}
});
}
}
}