Skip to content

Commit

Permalink
Po 746 put draft accounts (#556)
Browse files Browse the repository at this point in the history
* add cache plus refactor

* resolve conflicts

* replace draft accounts PUT

* fix(deps): update flyway to v10.18.1

* Revert "PO-802 make test user 1 both an inputter and a checker (#546)" (#552)

This reverts commit d416df3.

Co-authored-by: Dan Lysiak <50049163+danlysiak@users.noreply.github.com>

* PO-802 and 810 Reassign permissions to some users and remove duplicat… (#553)

* PO-802 and 810 Reassign permissions to some users and remove duplicate business units assigned to some users as a result of removing RM BUs

* adjustments to tests for corrected user data

---------

Co-authored-by: CadeFaulkner <cade.faulkner@hmcts.net>

* fix(deps): update junit5 monorepo

* fix(deps): update serenityversion to v4.2.3

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: abrahamdennis <148991960+abrahamdennis@users.noreply.github.com>
Co-authored-by: Dan Lysiak <50049163+danlysiak@users.noreply.github.com>
Co-authored-by: CadeFaulkner <cade.faulkner@hmcts.net>
  • Loading branch information
5 people authored Sep 27, 2024
1 parent 8c8dea7 commit e904895
Show file tree
Hide file tree
Showing 8 changed files with 331 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package uk.gov.hmcts.opal.controllers;

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.persistence.QueryTimeoutException;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
Expand All @@ -17,6 +18,7 @@
import org.springframework.test.web.servlet.MvcResult;
import uk.gov.hmcts.opal.authentication.service.AccessTokenService;
import uk.gov.hmcts.opal.controllers.advice.GlobalExceptionHandler;
import uk.gov.hmcts.opal.dto.ReplaceDraftAccountRequestDto;
import uk.gov.hmcts.opal.dto.ToJsonString;
import uk.gov.hmcts.opal.dto.search.DraftAccountSearchDto;
import uk.gov.hmcts.opal.entity.BusinessUnitEntity;
Expand All @@ -28,20 +30,25 @@

import java.net.ConnectException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.logging.Logger;

import static java.util.Collections.singletonList;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;


@WebMvcTest
@ContextConfiguration(classes = {DraftAccountController.class, GlobalExceptionHandler.class})
@ActiveProfiles({"integration"})
Expand All @@ -54,6 +61,9 @@ class DraftAccountControllerIntegrationTest {
@Autowired
MockMvc mockMvc;

@Autowired
private ObjectMapper objectMapper;

@MockBean
@Qualifier("draftAccountService")
DraftAccountService draftAccountService;
Expand Down Expand Up @@ -207,4 +217,83 @@ void testDeleteDraftAccountById() throws Exception {
String body = result.getResponse().getContentAsString();
logger.info(":testGetDraftAccountById: Response body:\n" + ToJsonString.toPrettyJson(body));
}

@Test
void testReplaceDraftAccount() throws Exception {
Long draftAccountId = 241L;
String requestBody = """
{
"account": {
"accountCreateRequest": {
"Defendant": {
"CompanyName": "Company ABC",
"Surname": "LNAME",
"Fornames": "FNAME",
"DOB": "2000-01-01"
},
"Account": {
"AccountType": "Fine"
}
}
},
"account_status": "",
"account_summary_data": "",
"account_type": "Fines",
"business_unit_id": 5,
"submitted_by": "BUUID1",
"timeline_data": {
"stuff": "yes"
},
"court": "test"
}
""";

LocalDateTime testDateTime = LocalDateTime.of(2024, 9, 26, 15, 0, 0);

DraftAccountEntity updatedEntity = DraftAccountEntity.builder()
.draftAccountId(draftAccountId)
.businessUnit(BusinessUnitEntity.builder().businessUnitId((short) 5)
.businessUnitName("Cambridgeshire").build())
.createdDate(testDateTime)
.submittedBy("BUUID1")
.account("{\"accountCreateRequest\":{\"Defendant\":{\"CompanyName\":\"Company ABC\",\"Surname\""
+ ":\"LNAME\",\"Fornames\":\"FNAME\",\"DOB\":\"2000-01-01\"},\"Account\""
+ ":{\"AccountType\":\"Fine\"}}}")
.accountSnapshot("{\"defendant_name\":\"Company ABC\",\"created_date\":\"2024-09-26T15:00:00Z\","
+ "\"account_type\":\"Fine\",\"submitted_by\":\"BUUID1\","
+ "\"business_unit_name\":\"Cambridgeshire\"}")
.accountType("Fines")
.accountStatus(DraftAccountStatus.RESUBMITTED)
.timelineData("{\"stuff\":\"yes\"}")
.build();

when(draftAccountService.replaceDraftAccount(eq(draftAccountId), any(ReplaceDraftAccountRequestDto.class)))
.thenReturn(updatedEntity);

MvcResult result = mockMvc.perform(put(URL_BASE + draftAccountId)
.header("authorization", "Bearer some_value")
.contentType(MediaType.APPLICATION_JSON)
.content(requestBody))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.draft_account_id").value(draftAccountId))
.andExpect(jsonPath("$.business_unit_id").value(5))
.andExpect(jsonPath("$.created_at").value("2024-09-26T15:00:00Z"))
.andExpect(jsonPath("$.submitted_by").value("BUUID1"))
.andExpect(jsonPath("$.account.accountCreateRequest.Defendant.CompanyName")
.value("Company ABC"))
.andExpect(jsonPath("$.account_snapshot.defendant_name").value("Company ABC"))
.andExpect(jsonPath("$.account_type").value("Fines"))
.andExpect(jsonPath("$.account_status").value("Resubmitted"))
.andExpect(jsonPath("$.timeline_data.stuff").value("yes"))
.andReturn();

String body = result.getResponse().getContentAsString();
logger.info(":testReplaceDraftAccount: Response body:\n" + ToJsonString.toPrettyJson(body));

assertTrue(jsonSchemaValidationService.isValid(body, "getDraftAccountResponse.json"));

verify(draftAccountService).replaceDraftAccount(eq(draftAccountId), any(ReplaceDraftAccountRequestDto.class));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import uk.gov.hmcts.opal.dto.AddDraftAccountRequestDto;
import uk.gov.hmcts.opal.dto.DraftAccountResponseDto;
import uk.gov.hmcts.opal.dto.ReplaceDraftAccountRequestDto;
import uk.gov.hmcts.opal.dto.search.DraftAccountSearchDto;
import uk.gov.hmcts.opal.entity.BusinessUnitEntity;
import uk.gov.hmcts.opal.entity.DraftAccountEntity;
Expand All @@ -40,6 +42,7 @@
public class DraftAccountController {

public static final String ADD_DRAFT_ACCOUNT_REQUEST_JSON = "addDraftAccountRequest.json";
public static final String REPLACE_DRAFT_ACCOUNT_REQUEST_JSON = "replaceDraftAccountRequest.json";
public static final String ACCOUNT_DELETED_MESSAGE_FORMAT = """
{ "message": "Draft Account '%s' deleted"}""";

Expand Down Expand Up @@ -119,6 +122,25 @@ public ResponseEntity<String> deleteDraftAccountById(
return buildResponse(String.format(ACCOUNT_DELETED_MESSAGE_FORMAT, draftAccountId));
}

@PutMapping(value = "/{draftAccountId}", consumes = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Replaces an existing Draft Account Entity in the DB with data in request body")
public ResponseEntity<DraftAccountResponseDto> replaceDraftAccount(
@PathVariable Long draftAccountId,
@RequestBody ReplaceDraftAccountRequestDto dto,
@RequestHeader(value = "Authorization", required = false) String authHeaderValue) {

log.info(":PUT:replaceDraftAccount: replacing draft account entity with ID: {} and data: {}",
draftAccountId, dto);

userStateService.checkForAuthorisedUser(authHeaderValue);

jsonSchemaValidationService.validateOrError(dto.toJson(), REPLACE_DRAFT_ACCOUNT_REQUEST_JSON);

DraftAccountEntity replacedEntity = draftAccountService.replaceDraftAccount(draftAccountId, dto);

return buildResponse(toGetResponseDto(replacedEntity));
}

DraftAccountResponseDto toGetResponseDto(DraftAccountEntity entity) {
return DraftAccountResponseDto.builder()
.draftAccountId(entity.getDraftAccountId())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
@AllArgsConstructor
@Builder
@JsonInclude(JsonInclude.Include.NON_NULL)
public class AddDraftAccountRequestDto implements ToJsonString {
public class AddDraftAccountRequestDto implements ToJsonString, DraftAccountRequestDto {

@JsonProperty("draft_account_id")
private Long draftAccountId;
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/uk/gov/hmcts/opal/dto/DraftAccountRequestDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package uk.gov.hmcts.opal.dto;

public interface DraftAccountRequestDto {

String getAccount();

Short getBusinessUnitId();

String getSubmittedBy();

String getAccountType();

String getTimelineData();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package uk.gov.hmcts.opal.dto;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRawValue;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import uk.gov.hmcts.opal.util.KeepAsJsonDeserializer;

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

@JsonProperty(value = "business_unit_id", required = true)
private Short businessUnitId;

@JsonProperty(value = "submitted_by", required = true)
private String submittedBy;

@JsonProperty("validated_by")
private String validatedBy;

@JsonProperty(value = "account", required = true)
@JsonDeserialize(using = KeepAsJsonDeserializer.class)
@JsonRawValue
private String account;

@JsonProperty(value = "account_type", required = true)
private String accountType;

@JsonProperty(value = "account_status", required = true)
private String accountStatus;

@JsonProperty(value = "timeline_data", required = true)
@JsonDeserialize(using = KeepAsJsonDeserializer.class)
@JsonRawValue
private String timelineData;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import uk.gov.hmcts.opal.dto.AddDraftAccountRequestDto;
import uk.gov.hmcts.opal.dto.DraftAccountRequestDto;
import uk.gov.hmcts.opal.dto.ReplaceDraftAccountRequestDto;
import uk.gov.hmcts.opal.entity.DraftAccountSnapshots;
import uk.gov.hmcts.opal.dto.search.DraftAccountSearchDto;
import uk.gov.hmcts.opal.entity.BusinessUnitEntity;
Expand Down Expand Up @@ -63,6 +65,8 @@ public List<DraftAccountEntity> searchDraftAccounts(DraftAccountSearchDto criter
return page.getContent();
}



public DraftAccountEntity submitDraftAccount(AddDraftAccountRequestDto dto) {
LocalDateTime created = LocalDateTime.now();
BusinessUnitEntity businessUnit = businessUnitRepository.findById(dto.getBusinessUnitId()).orElse(null);
Expand All @@ -71,7 +75,29 @@ public DraftAccountEntity submitDraftAccount(AddDraftAccountRequestDto dto) {
return draftAccountRepository.save(toEntity(dto, created, businessUnit, snapshot));
}

private String createInitialSnapshot(AddDraftAccountRequestDto dto, LocalDateTime created,
public DraftAccountEntity replaceDraftAccount(Long draftAccountId, ReplaceDraftAccountRequestDto dto) {
DraftAccountEntity existingAccount = draftAccountRepository.findById(draftAccountId)
.orElseThrow(() -> new RuntimeException("Draft Account not found with id: " + draftAccountId));

BusinessUnitEntity businessUnit = businessUnitRepository.findById(dto.getBusinessUnitId())
.orElseThrow(() -> new RuntimeException("Business Unit not found with id: " + dto.getBusinessUnitId()));

LocalDateTime updatedTime = LocalDateTime.now();
String newSnapshot = createInitialSnapshot(dto, updatedTime, businessUnit);
existingAccount.setSubmittedBy(dto.getSubmittedBy());
existingAccount.setAccount(dto.getAccount());
existingAccount.setAccountSnapshot(newSnapshot);
existingAccount.setAccountType(dto.getAccountType());
existingAccount.setAccountStatus(DraftAccountStatus.RESUBMITTED);
existingAccount.setTimelineData(dto.getTimelineData());

log.info(":replaceDraftAccount: Replacing draft account with ID: {} and new snapshot: \n{}",
draftAccountId, newSnapshot);

return draftAccountRepository.save(existingAccount);
}

private String createInitialSnapshot(DraftAccountRequestDto dto, LocalDateTime created,
BusinessUnitEntity businessUnit) {
return buildInitialSnapshot(dto.getAccount(), created, businessUnit, dto.getSubmittedBy()).toPrettyJson();
}
Expand Down Expand Up @@ -105,7 +131,7 @@ private DraftAccountSnapshots.Snapshot buildInitialSnapshot(String document, L
.build();
}

DraftAccountEntity toEntity(AddDraftAccountRequestDto dto, LocalDateTime created,
DraftAccountEntity toEntity(DraftAccountRequestDto dto, LocalDateTime created,
BusinessUnitEntity businessUnit, String snapshot) {
return DraftAccountEntity.builder()
.businessUnit(businessUnit)
Expand Down
44 changes: 44 additions & 0 deletions src/main/resources/jsonSchemas/replaceDraftAccountRequest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://opal-fines-service/replaceDraftAccountRequest.json",
"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"
},
"validated_by": {
"type": "string",
"description": "ID of the User that validated the Draft Account for checking"
},
"account": {
"type": "object",
"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": "object",
"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"
]
}
Loading

0 comments on commit e904895

Please sign in to comment.