Skip to content

Commit

Permalink
PO-559: Update DraftAccount POST endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
RustyHMCTS committed Aug 23, 2024
1 parent 7b6883e commit 50e19d2
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ void testGetDraftAccountById() throws Exception {

when(draftAccountService.getDraftAccount(1L)).thenReturn(draftAccountEntity);

MvcResult result = mockMvc.perform(get("/api/draft-account/1")
MvcResult result = mockMvc.perform(get("/api/draft-accounts/1")
.header("authorization", "Bearer some_value"))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
Expand All @@ -81,7 +81,7 @@ void testGetDraftAccountById() throws Exception {
void testGetDraftAccountById_WhenDraftAccountDoesNotExist() throws Exception {
when(draftAccountService.getDraftAccount(2L)).thenReturn(null);

mockMvc.perform(get("/api/draft-account/2").header("authorization", "Bearer some_value"))
mockMvc.perform(get("/api/draft-accounts/2").header("authorization", "Bearer some_value"))
.andExpect(status().isNoContent());
}

Expand All @@ -92,7 +92,7 @@ void testPostDraftAccountsSearch() throws Exception {
when(draftAccountService.searchDraftAccounts(any(DraftAccountSearchDto.class)))
.thenReturn(singletonList(draftAccountEntity));

mockMvc.perform(post("/api/draft-account/search")
mockMvc.perform(post("/api/draft-accounts/search")
.header("authorization", "Bearer some_value")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"criteria\":\"value\"}"))
Expand All @@ -107,7 +107,7 @@ void testPostDraftAccountsSearch() throws Exception {

@Test
void testPostDraftAccountsSearch_WhenDraftAccountDoesNotExist() throws Exception {
mockMvc.perform(post("/api/draft-account/search")
mockMvc.perform(post("/api/draft-accounts/search")
.header("authorization", "Bearer some_value")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"criteria\":\"2\"}"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import uk.gov.hmcts.opal.dto.AddDraftAccountRequestDto;
import uk.gov.hmcts.opal.dto.GetDraftAccountResponseDto;
import uk.gov.hmcts.opal.dto.search.DraftAccountSearchDto;
import uk.gov.hmcts.opal.entity.DraftAccountEntity;
Expand All @@ -23,15 +24,18 @@
import java.util.Optional;

import static uk.gov.hmcts.opal.util.DateTimeUtils.toOffsetDateTime;
import static uk.gov.hmcts.opal.util.HttpUtil.buildCreatedResponse;
import static uk.gov.hmcts.opal.util.HttpUtil.buildResponse;


@RestController
@RequestMapping("/api/draft-account")
@RequestMapping("/api/draft-accounts")
@Slf4j(topic = "DraftAccountController")
@Tag(name = "DraftAccount Controller")
public class DraftAccountController {

public static final String ADD_DRAFT_ACCOUNT_REQUEST_JSON = "addDraftAccountRequest.json";

private final DraftAccountService draftAccountService;

private final UserStateService userStateService;
Expand Down Expand Up @@ -74,16 +78,18 @@ public ResponseEntity<List<DraftAccountEntity>> postDraftAccountsSearch(@Request
}

@PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Creates a Draft Account entity in the DB based upon data in request body")
public ResponseEntity<DraftAccountEntity> postDraftAccount(@RequestBody DraftAccountEntity entity,
@Operation(summary = "Creates a Draft Account Entity in the DB based upon data in request body")
public ResponseEntity<DraftAccountEntity> postDraftAccount(@RequestBody AddDraftAccountRequestDto dto,
@RequestHeader(value = "Authorization", required = false) String authHeaderValue) {
log.info(":POST:postDraftAccount: creating a new draft account entity.");

userStateService.checkForAuthorisedUser(authHeaderValue);

DraftAccountEntity response = draftAccountService.saveDraftAccount(entity);
jsonSchemaValidationService.validateOrError(dto.toJson(), ADD_DRAFT_ACCOUNT_REQUEST_JSON);

return buildResponse(response);
DraftAccountEntity response = draftAccountService.saveDraftAccount(dto);

return buildCreatedResponse(response);
}

GetDraftAccountResponseDto toGetResponseDto(DraftAccountEntity entity) {
Expand All @@ -103,4 +109,5 @@ GetDraftAccountResponseDto toGetResponseDto(DraftAccountEntity entity) {
.accountId(entity.getAccountId())
.build();
}

}
57 changes: 57 additions & 0 deletions src/main/java/uk/gov/hmcts/opal/dto/AddDraftAccountRequestDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package uk.gov.hmcts.opal.dto;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.OffsetDateTime;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@JsonInclude(JsonInclude.Include.NON_NULL)
public class AddDraftAccountRequestDto implements ToJsonString {

@JsonProperty("draft_account_id")
private Long draftAccountId;

@JsonProperty("business_unit_id")
private Short businessUnitId;

@JsonProperty("created_at")
private OffsetDateTime createdDate;

@JsonProperty("submitted_by")
private String submittedBy;

@JsonProperty("validated_at")
private OffsetDateTime validatedDate;

@JsonProperty("validated_by")
private String validatedBy;

@JsonProperty("account")
private String account;

@JsonProperty("account_snapshot")
private String accountSnapshot;

@JsonProperty("account_type")
private String accountType;

@JsonProperty("account_status")
private String accountStatus;

@JsonProperty("timeline_data")
private String timelineData;

@JsonProperty("account_number")
private String accountNumber;

@JsonProperty("account_id")
private Long accountId;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import uk.gov.hmcts.opal.dto.AddDraftAccountRequestDto;
import uk.gov.hmcts.opal.dto.search.DraftAccountSearchDto;
import uk.gov.hmcts.opal.entity.DraftAccountEntity;
import uk.gov.hmcts.opal.repository.BusinessUnitRepository;
import uk.gov.hmcts.opal.repository.DraftAccountRepository;
import uk.gov.hmcts.opal.repository.jpa.DraftAccountSpecs;
import uk.gov.hmcts.opal.service.DraftAccountServiceInterface;

import java.time.OffsetDateTime;
import java.util.List;
import java.util.Optional;

@Service
@RequiredArgsConstructor
Expand All @@ -21,6 +25,8 @@ public class DraftAccountService implements DraftAccountServiceInterface {

private final DraftAccountRepository draftAccountRepository;

private final BusinessUnitRepository businessUnitRepository;

private final DraftAccountSpecs specs = new DraftAccountSpecs();

@Override
Expand All @@ -37,8 +43,27 @@ public List<DraftAccountEntity> searchDraftAccounts(DraftAccountSearchDto criter
return page.getContent();
}

public DraftAccountEntity saveDraftAccount(DraftAccountEntity entity) {
return draftAccountRepository.save(entity);
public DraftAccountEntity saveDraftAccount(AddDraftAccountRequestDto dto) {
return draftAccountRepository.save(toEntity(dto));
}

DraftAccountEntity toEntity(AddDraftAccountRequestDto dto) {
return DraftAccountEntity.builder()
.draftAccountId(dto.getDraftAccountId())
.businessUnit(businessUnitRepository.getReferenceById(dto.getBusinessUnitId()))
.createdDate(Optional.ofNullable(dto.getCreatedDate())
.map(OffsetDateTime::toLocalDateTime).orElse(null))
.submittedBy(dto.getSubmittedBy())
.validatedDate(Optional.ofNullable(dto.getValidatedDate())
.map(OffsetDateTime::toLocalDateTime).orElse(null))
.validatedBy(dto.getValidatedBy())
.account(dto.getAccount())
.accountSnapshot(dto.getAccountSnapshot())
.accountType(dto.getAccountType())
.accountStatus(dto.getAccountStatus())
.timelineData(dto.getTimelineData())
.accountNumber(dto.getAccountNumber())
.accountId(dto.getAccountId())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.networknt.schema.JsonSchema;
import com.networknt.schema.JsonSchemaFactory;
import com.networknt.schema.SpecVersion;
import com.networknt.schema.ValidationMessage;
Expand All @@ -16,6 +17,8 @@
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

Expand All @@ -27,6 +30,8 @@ public class JsonSchemaValidationService {

private static final String PATH_ROOT = "jsonSchemas";

private static final Map<String, JsonSchema> schemaCache = new HashMap<>(37);

public boolean isValid(String body, String jsonSchemaFileName) {
Set<String> errors = validate(body, jsonSchemaFileName);
if (!errors.isEmpty()) {
Expand Down Expand Up @@ -56,8 +61,7 @@ public void validateOrError(String body, String jsonSchemaFileName) {
}

public Set<String> validate(String body, String jsonSchemaFileName) {
String jsonSchemaContents = readJsonSchema(jsonSchemaFileName);
var jsonSchema = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7).getSchema(jsonSchemaContents);
JsonSchema jsonSchema = getJsonSchema(jsonSchemaFileName);
try {
Set<ValidationMessage> msgs = jsonSchema.validate(getJsonNodeFromStringContent(body));
return msgs.stream().map(ValidationMessage::getMessage).collect(Collectors.toSet());
Expand All @@ -79,7 +83,17 @@ private JsonNode getJsonNodeFromStringContent(String content) {
}
}

private String readJsonSchema(String schemaFileName) {
private JsonSchema getJsonSchema(String schemaFileName) {
if (schemaCache.containsKey(schemaFileName)) {
return schemaCache.get(schemaFileName);
}
String fileContents = readJsonSchemaFileContents(schemaFileName);
JsonSchema jsonSchema = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7).getSchema(fileContents);
schemaCache.put(schemaFileName, jsonSchema);
return jsonSchema;
}

private String readJsonSchemaFileContents(String schemaFileName) {
if (schemaFileName.isBlank()) {
throw new SchemaConfigurationException("A schema filename is required to validate a JSON document.");
}
Expand Down
39 changes: 39 additions & 0 deletions src/main/resources/jsonSchemas/addDraftAccountRequest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"business_unit_id": {
"type": "integer",
"format": "int32",
"description": "ID of the Business Unit the Draft Account belongs to"
},
"submitted_by": {
"type": "string",
"description": "ID of the User that last submitted the Draft Account for checking"
},
"account": {
"type": "string",
"description": "The structured Account data (JSON)"
},
"account_type": {
"type": "string",
"description": "Type of Account, such as Fixed Penalty Registration"
},
"account_status": {
"type": "string",
"description": "Status of the Draft Account - one of Submitted, Resubmitted, Rejected, Approved, Deleted"
},
"timeline_data": {
"type": "string",
"description": "Status changes to the Draft Account in chronological order (JSON Array) - System generated (UI)"
}
},
"required": [
"business_unit_id",
"submitted_by",
"account",
"account_type",
"account_status",
"timeline_data"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import uk.gov.hmcts.opal.dto.AddDraftAccountRequestDto;
import uk.gov.hmcts.opal.dto.GetDraftAccountResponseDto;
import uk.gov.hmcts.opal.dto.search.DraftAccountSearchDto;
import uk.gov.hmcts.opal.entity.BusinessUnitEntity;
Expand Down Expand Up @@ -84,15 +85,23 @@ void testSearchDraftAccounts_Success() {
void testSaveDraftAccounts_Success() {
// Arrange
DraftAccountEntity entity = DraftAccountEntity.builder().build();
AddDraftAccountRequestDto addDraftAccountDto = AddDraftAccountRequestDto.builder()
.accountType("Large")
.accountStatus("Brand New")
.account("")
.businessUnitId((short)1)
.submittedBy("Charles")
.timelineData("")
.build();

when(draftAccountService.saveDraftAccount(any())).thenReturn(entity);

// Act
ResponseEntity<DraftAccountEntity> response = draftAccountController.postDraftAccount(
entity, BEARER_TOKEN);
addDraftAccountDto, BEARER_TOKEN);

// Assert
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals(HttpStatus.CREATED, response.getStatusCode());
assertEquals(entity, response.getBody());
verify(draftAccountService, times(1)).saveDraftAccount(any());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.repository.query.FluentQuery;
import uk.gov.hmcts.opal.dto.AddDraftAccountRequestDto;
import uk.gov.hmcts.opal.dto.search.DraftAccountSearchDto;
import uk.gov.hmcts.opal.entity.BusinessUnitEntity;
import uk.gov.hmcts.opal.entity.DraftAccountEntity;
import uk.gov.hmcts.opal.repository.BusinessUnitRepository;
import uk.gov.hmcts.opal.repository.DraftAccountRepository;

import java.util.List;
Expand All @@ -29,6 +32,9 @@ class DraftAccountServiceTest {
@Mock
private DraftAccountRepository draftAccountRepository;

@Mock
private BusinessUnitRepository businessUnitRepository;

@InjectMocks
private DraftAccountService draftAccountService;

Expand Down Expand Up @@ -74,11 +80,14 @@ void testSearchDraftAccounts() {
void testSaveDraftAccounts() {
// Arrange
DraftAccountEntity draftAccountEntity = DraftAccountEntity.builder().build();
AddDraftAccountRequestDto addDraftAccountDto = AddDraftAccountRequestDto.builder().build();
BusinessUnitEntity businessUnit = BusinessUnitEntity.builder().build();

when(businessUnitRepository.getReferenceById(any())).thenReturn(businessUnit);
when(draftAccountRepository.save(any(DraftAccountEntity.class))).thenReturn(draftAccountEntity);

// Act
DraftAccountEntity result = draftAccountService.saveDraftAccount(draftAccountEntity);
DraftAccountEntity result = draftAccountService.saveDraftAccount(addDraftAccountDto);

// Assert
assertEquals(draftAccountEntity, result);
Expand Down

0 comments on commit 50e19d2

Please sign in to comment.