Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MAT-7938: implement CMS id delete endpoint #759

Merged
merged 7 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,20 @@ public ResponseEntity<MeasureSet> createCmsId(
.body(measureSetService.createAndUpdateCmsId(measureSetId, principal.getName()));
}

@DeleteMapping("/measures/{measureId}/delete-cms-id")
@PreAuthorize("#request.getHeader('api-key') == #apiKey")
public ResponseEntity<String> deleteCmsId(
HttpServletRequest request,
@PathVariable String measureId,
@RequestParam(name = "cmsId") Integer cmsId,
@Value("${admin-api-key}") String apiKey,
Principal principal) {
log.info("User [{}] - Started admin task [deleteCmsId] and is attempting to delete " +
"CMS id [{}] from measure with measure id [{}]", principal.getName(), cmsId, measureId);
return ResponseEntity.status(HttpStatus.OK)
.body(measureSetService.deleteCmsId(measureId, cmsId));
}

@PutMapping("/measures/cms-id-association")
public ResponseEntity<MeasureSet> associateCmsId(
Principal principal,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import cms.gov.madie.measure.exceptions.*;
import cms.gov.madie.measure.repositories.GeneratorRepository;
import cms.gov.madie.measure.repositories.MeasureRepository;
import cms.gov.madie.measure.repositories.MeasureSetRepository;
import gov.cms.madie.models.access.AclOperation;
import gov.cms.madie.models.access.AclSpecification;
Expand All @@ -13,6 +14,7 @@
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.Optional;

Expand All @@ -21,6 +23,7 @@
@RequiredArgsConstructor
public class MeasureSetService {

private final MeasureRepository measureRepository;
private final MeasureSetRepository measureSetRepository;
private final GeneratorRepository generatorRepository;
private final ActionLogService actionLogService;
Expand Down Expand Up @@ -147,6 +150,53 @@ public MeasureSet createAndUpdateCmsId(String measureSetId, String username) {
return updatedMeasureSet;
}

public String deleteCmsId(String measureId, Integer cmsId) {
Optional<Measure> measure = measureRepository.findById(measureId);

if (measure.isPresent()) {
String measureSetId = measure.get().getMeasureSetId();
Optional<MeasureSet> optionalMeasureSet = measureSetRepository.findByMeasureSetId(measureSetId);

if (optionalMeasureSet.isEmpty()) {
throw new ResourceNotFoundException("No measure set exists for measure with measure set id of "
+ measureSetId);
}

MeasureSet measureSet = optionalMeasureSet.get();

if (measureSet.getCmsId() == null) {
throw new ResourceNotFoundException(String.format("No CMS id of %s exists to be deleted " +
"within measure set with measure set id of %s", cmsId, measureSetId));
}

if (!measureSet.getCmsId().equals(cmsId)) {
throw new InvalidIdException(
String.format("CMS id of %s passed in does not match CMS id of %s within " +
"measure set with measure set id of %s", cmsId,measureSet.getCmsId(), measureSetId));
}

List<Measure> measures = measureRepository.findAllByMeasureSetIdAndActive(measureSetId, true);

if (measures.size() > 1) {
throw new InvalidRequestException(String.format("Measure set with measure set id of %s contains more than 1 measure. " +
"Cannot delete CMS id when measure set has more than 1 version of measure.", measureSetId));
}

measureSet.setCmsId(null);
measureSetRepository.save(measureSet);

log.info("With the measure id of [{}], successfully queried " +
"for its measure set with measure set id of [{}] and deleted CMS id " +
"of [{}] from the measure set", measureId, measureSetId, cmsId);

return String.format("CMS id of %s was deleted successfully from " +
"measure set with measure set id of %s", cmsId, measureSetId);
} else {
throw new ResourceNotFoundException(
"No measure exists with measure id of " + measureId);
}
}

public MeasureSet findByMeasureSetId(final String measureSetId) {
return measureSetRepository.findByMeasureSetId(measureSetId).orElse(null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.mock.web.MockHttpServletRequest;

import java.io.UnsupportedEncodingException;
import java.security.Principal;
Expand Down Expand Up @@ -262,6 +263,33 @@ void createCmsId() {
verify(measureSetService, times(1)).createAndUpdateCmsId(anyString(), anyString());
}

@Test
void deleteCmsId() {
Principal principal = mock(Principal.class);
MockHttpServletRequest mockHttpServletRequest = new MockHttpServletRequest();

String measureId = "measureId";

final MeasureSet measureSet =
MeasureSet.builder()
.id("f225481c-921e-4015-9e14-e5046bfac9ff")
.cmsId(6)
.measureSetId("measureSetId")
.owner("owner")
.acls(null)
.build();

String expectedBody = String.format("CMS Id of %s was deleted successfully from measure set with measure set id of %s", measureSet.getCmsId(), measureSet.getMeasureSetId());

when(measureSetService.deleteCmsId(anyString(), anyInt())).thenReturn(expectedBody);

ResponseEntity<String> response = controller.deleteCmsId(mockHttpServletRequest, measureId, measureSet.getCmsId(), "apiKey", principal);

assertThat(response.getBody(), is(notNullValue()));
assertEquals(expectedBody, response.getBody());
verify(measureSetService, times(1)).deleteCmsId(anyString(), anyInt());
}

@Test
void updateMeasureSuccessfullyLogDeleted() {
ArgumentCaptor<Measure> saveMeasureArgCaptor = ArgumentCaptor.forClass(Measure.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package cms.gov.madie.measure.services;

import cms.gov.madie.measure.exceptions.InvalidIdException;
import cms.gov.madie.measure.exceptions.InvalidRequestException;
import cms.gov.madie.measure.exceptions.ResourceNotFoundException;
import cms.gov.madie.measure.repositories.GeneratorRepository;
import cms.gov.madie.measure.repositories.MeasureRepository;
import cms.gov.madie.measure.repositories.MeasureSetRepository;
import gov.cms.madie.models.access.AclOperation;
import gov.cms.madie.models.access.AclSpecification;
import gov.cms.madie.models.access.RoleEnum;
import gov.cms.madie.models.common.ActionType;
import gov.cms.madie.models.common.ModelType;
import gov.cms.madie.models.measure.Measure;
import gov.cms.madie.models.measure.MeasureSet;
import org.junit.jupiter.api.BeforeEach;
Expand All @@ -22,14 +25,14 @@
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
public class MeasureSetServiceTest {

@InjectMocks private MeasureSetService measureSetService;
@Mock MeasureRepository measureRepository;
@Mock MeasureSetRepository measureSetRepository;
@Mock GeneratorRepository generatorRepository;
@Mock private ActionLogService actionLogService;
Expand Down Expand Up @@ -256,4 +259,168 @@ public void testCreateCmsIdWhenCmsIdAlreadyExistsInMeasureSet() {
verify(measureSetRepository, times(1)).findByMeasureSetId(anyString());
verify(measureSetRepository, times(0)).save(any(MeasureSet.class));
}

@Test
public void testDeleteCmsId() {
Integer cmsId = 1;
Measure measure =
Measure.builder()
.model(ModelType.QI_CORE.getValue())
.measureSetId("measureSetId1")
.build();

List<Measure> measures = Collections.singletonList(measure);
MeasureSet measureSet = MeasureSet.builder().measureSetId("1").cmsId(1).build();
String measureId = "measureId";

when(measureRepository.findById(anyString())).thenReturn(Optional.of( measure));
when(measureSetRepository.findByMeasureSetId(anyString())).thenReturn(Optional.of(measureSet));
when(measureRepository.findAllByMeasureSetIdAndActive(anyString(), anyBoolean())).thenReturn(measures);
when(measureSetRepository.save(any(MeasureSet.class))).thenReturn(measureSet);

String responseBody = measureSetService.deleteCmsId(measureId, cmsId);

assertEquals(responseBody, String.format("CMS id of %s was deleted successfully from measure set with measure set id of %s", cmsId, measure.getMeasureSetId()));
verify(measureRepository, times(1)).findById(anyString());
verify(measureSetRepository, times(1)).findByMeasureSetId(anyString());
verify(measureRepository, times(1)).findAllByMeasureSetIdAndActive(anyString(), anyBoolean());
verify(measureSetRepository, times(1)).save(any(MeasureSet.class));
}

@Test
public void testDeleteCmsIdWhenMeasureWithMeasureIdIsNotFound() {
String measureId = "measureId";

when(measureRepository.findById(anyString())).thenReturn(Optional.empty());

Exception ex =
assertThrows(
ResourceNotFoundException.class,
() -> measureSetService.deleteCmsId(measureId, 1));

assertTrue(
ex.getMessage()
.contains(String.format("No measure exists with measure id of %s", measureId)));
verify(measureRepository, times(1)).findById(anyString());
verify(measureSetRepository, times(0)).save(any(MeasureSet.class));
verify(measureSetRepository, times(0)).save(any(MeasureSet.class));
}

@Test
public void testDeleteCmsIdWhenMeasureSetIsNotFound() {
Measure measure =
Measure.builder()
.model(ModelType.QI_CORE.getValue())
.measureSetId("measureSetId")
.build();

String measureId = "measureId";

when(measureRepository.findById(anyString())).thenReturn(Optional.of( measure));
when(measureSetRepository.findByMeasureSetId(anyString())).thenReturn(Optional.empty());

Exception ex =
assertThrows(
ResourceNotFoundException.class,
() -> measureSetService.deleteCmsId(measureId, 1));

assertTrue(
ex.getMessage()
.contains(String.format("No measure set exists for measure with measure set id of %s", measure.getMeasureSetId())));
verify(measureRepository, times(1)).findById(anyString());
verify(measureSetRepository, times(1)).findByMeasureSetId(anyString());
verify(measureSetRepository, times(0)).save(any(MeasureSet.class));
}

@Test
public void testDeleteCmsIdWhenCmsIdIsNotFoundInMeasureSet() {
Integer cmsId = 1;
Measure measure =
Measure.builder()
.model(ModelType.QI_CORE.getValue())
.measureSetId("measureSetId")
.build();

MeasureSet measureSet = MeasureSet.builder().measureSetId("1").build();
String measureId = "measureId";

when(measureRepository.findById(anyString())).thenReturn(Optional.of( measure));
when(measureSetRepository.findByMeasureSetId(anyString())).thenReturn(Optional.of(measureSet));

Exception ex =
assertThrows(
ResourceNotFoundException.class,
() -> measureSetService.deleteCmsId(measureId, cmsId));

assertTrue(
ex.getMessage()
.contains(String.format("No CMS id of %s exists to be deleted within measure set with measure set id of %s", cmsId, measure.getMeasureSetId())));
verify(measureRepository, times(1)).findById(anyString());
verify(measureSetRepository, times(1)).findByMeasureSetId(anyString());
verify(measureSetRepository, times(0)).save(any(MeasureSet.class));
}

@Test
public void testDeleteCmsIdWhenCmsIdToDeleteDoesNotMatchCmsIdInMeasureSet() {
Integer cmsId = 1;
Measure measure =
Measure.builder()
.model(ModelType.QI_CORE.getValue())
.measureSetId("measureSetId")
.build();

MeasureSet measureSet = MeasureSet.builder().measureSetId("1").cmsId(2).build();
String measureId = "measureId";

when(measureRepository.findById(anyString())).thenReturn(Optional.of( measure));
when(measureSetRepository.findByMeasureSetId(anyString())).thenReturn(Optional.of(measureSet));

Exception ex =
assertThrows(
InvalidIdException.class,
() -> measureSetService.deleteCmsId(measureId, cmsId));

assertTrue(
ex.getMessage()
.contains(String.format("CMS id of %s passed in does not match CMS id of %s within measure set with measure set id of %s", cmsId, measureSet.getCmsId(), measure.getMeasureSetId())));
verify(measureRepository, times(1)).findById(anyString());
verify(measureSetRepository, times(1)).findByMeasureSetId(anyString());
verify(measureSetRepository, times(0)).save(any(MeasureSet.class));
}
@Test
public void testDeleteCmsIdWhenMeasureHasMultipleVersions() {
Integer cmsId = 1;
Measure measure1 =
Measure.builder()
.model(ModelType.QI_CORE.getValue())
.measureSetId("measureSetId1")
.build();

Measure measure2 =
Measure.builder()
.model(ModelType.QI_CORE.getValue())
.measureSetId("measureSetId2")
.build();

List<Measure> measures = Arrays.asList(measure1, measure2);
MeasureSet measureSet = MeasureSet.builder().measureSetId("1").cmsId(1).build();
String measureId = "measureId";

when(measureRepository.findById(anyString())).thenReturn(Optional.of( measure1));
when(measureSetRepository.findByMeasureSetId(anyString())).thenReturn(Optional.of(measureSet));
when(measureRepository.findAllByMeasureSetIdAndActive(anyString(), anyBoolean())).thenReturn(measures);

Exception ex =
assertThrows(
InvalidRequestException.class,
() -> measureSetService.deleteCmsId(measureId, cmsId));

assertTrue(
ex.getMessage()
.contains(String.format(String.format("Measure set with measure set id of %s contains more than 1 measure. Cannot delete CMS id when measure set has more than 1 version of measure.", measure1.getMeasureSetId()))));
verify(measureRepository, times(1)).findById(anyString());
verify(measureSetRepository, times(1)).findByMeasureSetId(anyString());
verify(measureRepository, times(1)).findAllByMeasureSetIdAndActive(anyString(), anyBoolean());
verify(measureSetRepository, times(0)).save(any(MeasureSet.class));
}
}
Loading