From ff65fdd7d444df44032df9d399b3c7180536dab2 Mon Sep 17 00:00:00 2001 From: Paulo Gomes da Cruz Junior Date: Tue, 16 Jan 2024 13:52:21 -0800 Subject: [PATCH 01/12] fix(FSADT1-1144): updating 100% match updated 100% match query to look for client identification for any kind. This allows a simples reuse of the query to match other things --- .../java/ca/bc/gov/app/repository/ForestClientRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/legacy/src/main/java/ca/bc/gov/app/repository/ForestClientRepository.java b/legacy/src/main/java/ca/bc/gov/app/repository/ForestClientRepository.java index 616a2017a3..fa3501c746 100644 --- a/legacy/src/main/java/ca/bc/gov/app/repository/ForestClientRepository.java +++ b/legacy/src/main/java/ca/bc/gov/app/repository/ForestClientRepository.java @@ -19,7 +19,7 @@ public interface ForestClientRepository extends ReactiveCrudRepository findClientByIncorporationOrName( @Param("incorporationNumber") String incorporationNumber, @Param("companyName") String companyName From c078853e4abcbed22c67289e7b7bdefe640805ec Mon Sep 17 00:00:00 2001 From: Paulo Gomes da Cruz Junior Date: Tue, 16 Jan 2024 14:01:29 -0800 Subject: [PATCH 02/12] fix(FSADT1-1141): updating username that is saved --- backend/src/main/java/ca/bc/gov/app/ApplicationConstant.java | 1 + .../app/controller/client/ClientSubmissionController.java | 4 +++- .../bc/gov/app/service/client/ClientSubmissionService.java | 5 +++-- .../client/ClientSubmissionControllerIntegrationTest.java | 4 ++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/backend/src/main/java/ca/bc/gov/app/ApplicationConstant.java b/backend/src/main/java/ca/bc/gov/app/ApplicationConstant.java index 84db79eec2..29f3ce2821 100644 --- a/backend/src/main/java/ca/bc/gov/app/ApplicationConstant.java +++ b/backend/src/main/java/ca/bc/gov/app/ApplicationConstant.java @@ -15,6 +15,7 @@ public final class ApplicationConstant { public static final String POSTGRES_ATTRIBUTE_SCHEMA = "nrfc"; public static final String USERID_HEADER = "x-user-id"; + public static final String BUSINESSID_HEADER = "x-user-businessid"; public static final String USERMAIL_HEADER = "x-user-email"; public static final String USERNAME_HEADER = "x-user-name"; diff --git a/backend/src/main/java/ca/bc/gov/app/controller/client/ClientSubmissionController.java b/backend/src/main/java/ca/bc/gov/app/controller/client/ClientSubmissionController.java index 9c976ea80c..f6def36c16 100644 --- a/backend/src/main/java/ca/bc/gov/app/controller/client/ClientSubmissionController.java +++ b/backend/src/main/java/ca/bc/gov/app/controller/client/ClientSubmissionController.java @@ -13,6 +13,7 @@ import ca.bc.gov.app.validator.client.ClientSubmitRequestValidator; import java.util.List; import java.util.Map; +import org.apache.commons.lang3.StringUtils; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpResponse; @@ -77,6 +78,7 @@ public Flux listSubmissions( public Mono submit( @RequestBody ClientSubmissionDto request, @RequestHeader(ApplicationConstant.USERID_HEADER) String userId, + @RequestHeader(name = ApplicationConstant.BUSINESSID_HEADER, defaultValue = StringUtils.EMPTY) String businessId, @RequestHeader(ApplicationConstant.USERMAIL_HEADER) String userEmail, @RequestHeader(ApplicationConstant.USERNAME_HEADER) String userName, ServerHttpResponse serverResponse) { @@ -85,7 +87,7 @@ public Mono submit( Mono.error(new InvalidRequestObjectException("no request body was provided")) ) .doOnNext(this::validate) - .flatMap(submissionDto -> clientService.submit(submissionDto, userId, userEmail, userName)) + .flatMap(submissionDto -> clientService.submit(submissionDto, userId, userEmail, userName,businessId)) .doOnNext(submissionId -> serverResponse .getHeaders() diff --git a/backend/src/main/java/ca/bc/gov/app/service/client/ClientSubmissionService.java b/backend/src/main/java/ca/bc/gov/app/service/client/ClientSubmissionService.java index da79f90f74..5c222ad498 100644 --- a/backend/src/main/java/ca/bc/gov/app/service/client/ClientSubmissionService.java +++ b/backend/src/main/java/ca/bc/gov/app/service/client/ClientSubmissionService.java @@ -128,7 +128,8 @@ public Mono submit( ClientSubmissionDto clientSubmissionDto, String userId, String userEmail, - String userName + String userName, + String businessId ) { return @@ -140,7 +141,7 @@ public Mono submit( .submissionType(SubmissionTypeCodeEnum.SPP) .submissionDate(LocalDateTime.now()) .createdBy(userId) - .updatedBy(userId) + .updatedBy(userName) .build() ) //Save submission to begin with diff --git a/backend/src/test/java/ca/bc/gov/app/controller/client/ClientSubmissionControllerIntegrationTest.java b/backend/src/test/java/ca/bc/gov/app/controller/client/ClientSubmissionControllerIntegrationTest.java index 48edf92daf..d0f22dfd72 100644 --- a/backend/src/test/java/ca/bc/gov/app/controller/client/ClientSubmissionControllerIntegrationTest.java +++ b/backend/src/test/java/ca/bc/gov/app/controller/client/ClientSubmissionControllerIntegrationTest.java @@ -213,7 +213,7 @@ void shouldListAndSearch( .jsonPath("$.[0].requestType").isEqualTo("Submission pending processing") .jsonPath("$.[0].status").isEqualTo("New") .jsonPath("$.[0].clientType").isEqualTo("Registered sole proprietorship") - .jsonPath("$.[0].user").isEqualTo("testUserId"); + .jsonPath("$.[0].user").isEqualTo("Test User"); } } @@ -229,7 +229,7 @@ void shouldGetSubmissionDetails() { .expectStatus().isOk() .expectBody() .jsonPath("$.submissionId").isEqualTo(1) - .jsonPath("$.updateUser").isEqualTo("testUserId") + .jsonPath("$.updateUser").isEqualTo("Test User") .jsonPath("$.submissionType").isEqualTo("Submission pending processing"); } From bb5f8164e5c0ec0a7e631456bb89c765a2ea32f2 Mon Sep 17 00:00:00 2001 From: Paulo Gomes da Cruz Junior Date: Tue, 16 Jan 2024 16:00:14 -0800 Subject: [PATCH 03/12] fix(FSADT1-1144): adding dba to 100% match --- .../ClientDoingBusinessAsRepository.java | 2 ++ .../repository/ForestClientRepository.java | 3 +++ .../gov/app/service/ClientSearchService.java | 23 +++++++++++++++++-- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/legacy/src/main/java/ca/bc/gov/app/repository/ClientDoingBusinessAsRepository.java b/legacy/src/main/java/ca/bc/gov/app/repository/ClientDoingBusinessAsRepository.java index d609a3164d..8b6de5cb5e 100644 --- a/legacy/src/main/java/ca/bc/gov/app/repository/ClientDoingBusinessAsRepository.java +++ b/legacy/src/main/java/ca/bc/gov/app/repository/ClientDoingBusinessAsRepository.java @@ -23,4 +23,6 @@ public interface ClientDoingBusinessAsRepository extends UTL_MATCH.JARO_WINKLER_SIMILARITY(UPPER(DOING_BUSINESS_AS_NAME),UPPER(:companyName)) >= 95 ORDER BY CLIENT_NUMBER""") Flux matchBy(String companyName); + + Flux findByDoingBusinessAsName(String doingBusinessAsName); } diff --git a/legacy/src/main/java/ca/bc/gov/app/repository/ForestClientRepository.java b/legacy/src/main/java/ca/bc/gov/app/repository/ForestClientRepository.java index fa3501c746..e542dbed77 100644 --- a/legacy/src/main/java/ca/bc/gov/app/repository/ForestClientRepository.java +++ b/legacy/src/main/java/ca/bc/gov/app/repository/ForestClientRepository.java @@ -9,6 +9,7 @@ import org.springframework.data.repository.reactive.ReactiveSortingRepository; import org.springframework.stereotype.Repository; import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; @Repository public interface ForestClientRepository extends ReactiveCrudRepository, @@ -44,4 +45,6 @@ AND UPPER(CLIENT_NAME) = UPPER(:lastName) ORDER BY CLIENT_NUMBER""") Flux matchBy(String companyName); + Mono findByClientNumber(String clientNumber); + } diff --git a/legacy/src/main/java/ca/bc/gov/app/service/ClientSearchService.java b/legacy/src/main/java/ca/bc/gov/app/service/ClientSearchService.java index 8b02612aa1..0c57665457 100644 --- a/legacy/src/main/java/ca/bc/gov/app/service/ClientSearchService.java +++ b/legacy/src/main/java/ca/bc/gov/app/service/ClientSearchService.java @@ -1,16 +1,20 @@ package ca.bc.gov.app.service; import ca.bc.gov.app.dto.ForestClientDto; +import ca.bc.gov.app.entity.ClientDoingBusinessAsEntity; import ca.bc.gov.app.entity.ForestClientEntity; import ca.bc.gov.app.exception.MissingRequiredParameterException; import ca.bc.gov.app.mappers.AbstractForestClientMapper; +import ca.bc.gov.app.repository.ClientDoingBusinessAsRepository; import ca.bc.gov.app.repository.ForestClientRepository; import java.time.LocalDate; +import java.util.Optional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; @Service @RequiredArgsConstructor @@ -18,6 +22,7 @@ public class ClientSearchService { private final ForestClientRepository forestClientRepository; + private final ClientDoingBusinessAsRepository doingBusinessAsRepository; private final AbstractForestClientMapper mapper; public Flux findByIncorporationOrName( @@ -32,8 +37,22 @@ public Flux findByIncorporationOrName( return forestClientRepository .findClientByIncorporationOrName(incorporationNumber, companyName) - .map(mapper::toDto) - .doOnNext(dto -> log.info("Found client: {} {}", dto.clientNumber(), dto.clientName())); + .doOnNext( + dto -> log.info("Found client: {} {}", dto.getClientNumber(), dto.getClientName())) + .switchIfEmpty( + Flux + .from(Mono.justOrEmpty(Optional.ofNullable(companyName))) + .filter(StringUtils::isNotBlank) + .flatMap(name -> + doingBusinessAsRepository + .findByDoingBusinessAsName(name.toUpperCase()) + .doOnNext(dto -> log.info("Found client doing business as: {} {}", + dto.getClientNumber(), dto.getDoingBusinessAsName())) + .map(ClientDoingBusinessAsEntity::getClientNumber) + .flatMap(forestClientRepository::findByClientNumber) + ) + ) + .map(mapper::toDto); } public Flux findByIndividual( From 2dd9b9b3bc19215594f19209cfe7e71727070d59 Mon Sep 17 00:00:00 2001 From: Paulo Gomes da Cruz Junior Date: Tue, 16 Jan 2024 16:23:14 -0800 Subject: [PATCH 04/12] fix(FSADT1-1144): adding id and lastname search --- .../controller/ClientSearchController.java | 8 ++++ .../repository/ForestClientRepository.java | 3 ++ .../gov/app/service/ClientSearchService.java | 9 +++++ ...ClientSearchControllerIntegrationTest.java | 37 ++++++++++++++++++- .../db/migration/V4__manual_data.sql | 2 +- 5 files changed, 56 insertions(+), 3 deletions(-) diff --git a/legacy/src/main/java/ca/bc/gov/app/controller/ClientSearchController.java b/legacy/src/main/java/ca/bc/gov/app/controller/ClientSearchController.java index b5a695822e..7712f07ad0 100644 --- a/legacy/src/main/java/ca/bc/gov/app/controller/ClientSearchController.java +++ b/legacy/src/main/java/ca/bc/gov/app/controller/ClientSearchController.java @@ -45,4 +45,12 @@ public Flux matchBy( return service.matchBy(companyName); } + @GetMapping("/idAndLastName") + public Flux findByIdAndLastName( + @RequestParam String clientId, + @RequestParam String lastName + ) { + return service.findByIdAndLastName(clientId, lastName); + } + } diff --git a/legacy/src/main/java/ca/bc/gov/app/repository/ForestClientRepository.java b/legacy/src/main/java/ca/bc/gov/app/repository/ForestClientRepository.java index e542dbed77..68e3cd682f 100644 --- a/legacy/src/main/java/ca/bc/gov/app/repository/ForestClientRepository.java +++ b/legacy/src/main/java/ca/bc/gov/app/repository/ForestClientRepository.java @@ -47,4 +47,7 @@ AND UPPER(CLIENT_NAME) = UPPER(:lastName) Mono findByClientNumber(String clientNumber); + + Flux findByClientIdentificationIgnoreCaseAndClientNameIgnoreCase(String clientIdentification, String clientName); + } diff --git a/legacy/src/main/java/ca/bc/gov/app/service/ClientSearchService.java b/legacy/src/main/java/ca/bc/gov/app/service/ClientSearchService.java index 0c57665457..1fc13c6383 100644 --- a/legacy/src/main/java/ca/bc/gov/app/service/ClientSearchService.java +++ b/legacy/src/main/java/ca/bc/gov/app/service/ClientSearchService.java @@ -81,4 +81,13 @@ public Flux matchBy(String companyName) { .map(mapper::toDto) .doOnNext(dto -> log.info("Found match: {} {}", dto.clientNumber(), dto.clientName())); } + + public Flux findByIdAndLastName(String clientId, String lastName) { + return forestClientRepository + .findByClientIdentificationIgnoreCaseAndClientNameIgnoreCase(clientId, lastName) + .map(mapper::toDto) + .doOnNext( + dto -> log.info("Found client: {} {}", dto.clientNumber(), dto.clientName()) + ); + } } diff --git a/legacy/src/test/java/ca/bc/gov/app/controller/ClientSearchControllerIntegrationTest.java b/legacy/src/test/java/ca/bc/gov/app/controller/ClientSearchControllerIntegrationTest.java index 6c99886d1c..1e27146b7d 100644 --- a/legacy/src/test/java/ca/bc/gov/app/controller/ClientSearchControllerIntegrationTest.java +++ b/legacy/src/test/java/ca/bc/gov/app/controller/ClientSearchControllerIntegrationTest.java @@ -161,7 +161,7 @@ void shouldSearchByIndividualFailures( void shouldMatch( String searchParam, String expected - ){ + ) { client .get() .uri(uriBuilder -> @@ -178,6 +178,30 @@ void shouldMatch( .consumeWith(System.out::println); } + @ParameterizedTest + @MethodSource("idLastName") + @DisplayName("Search someone by id and last name") + void shouldSearchByIdAndLastName(String clientId, String lastName) { + client + .get() + .uri(uriBuilder -> + uriBuilder + .path("/api/search/idAndLastName") + .queryParam("clientId", Optional.ofNullable(clientId)) + .queryParam("lastName", Optional.ofNullable(lastName)) + .build(new HashMap<>()) + ) + .header("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$[0].clientNumber").isNotEmpty() + .jsonPath("$[0].clientNumber").isEqualTo("00000007") + .jsonPath("$[0].clientName").isNotEmpty() + .jsonPath("$[0].clientName").isEqualTo("bond") + .consumeWith(System.out::println); + } + private static Stream byLastNameCompanyName() { return Stream.of("BAXTER", "BORIS AND BORIS INC."); } @@ -220,9 +244,18 @@ private static Stream legalName() { "corpRegnNmbr":null } ]"""), - Arguments.of("Marco","[]"), + Arguments.of("Marco", "[]"), Arguments.of("Lucca", "[]") ); } + private static Stream idLastName() { + return Stream + .of( + Arguments.of("Wull", "bond"), + Arguments.of("wull", "BOND"), + Arguments.of("wull", "BoNd") + ); + } + } diff --git a/legacy/src/test/resources/db/migration/V4__manual_data.sql b/legacy/src/test/resources/db/migration/V4__manual_data.sql index be17023099..b400ec559e 100644 --- a/legacy/src/test/resources/db/migration/V4__manual_data.sql +++ b/legacy/src/test/resources/db/migration/V4__manual_data.sql @@ -84,7 +84,7 @@ VALUES(client_dba_seq.NEXTVAL, '00000006', '00', 'TN', 'NEDAD KONTIC', '60466667 INSERT INTO THE.FOREST_CLIENT (CLIENT_NUMBER, CLIENT_NAME, LEGAL_FIRST_NAME, LEGAL_MIDDLE_NAME, CLIENT_STATUS_CODE, CLIENT_TYPE_CODE, BIRTHDATE, CLIENT_ID_TYPE_CODE, CLIENT_IDENTIFICATION, REGISTRY_COMPANY_TYPE_CODE, CORP_REGN_NMBR, CLIENT_ACRONYM, WCB_FIRM_NUMBER, OCG_SUPPLIER_NMBR, CLIENT_COMMENT, ADD_TIMESTAMP, ADD_USERID, ADD_ORG_UNIT, UPDATE_TIMESTAMP, UPDATE_USERID, UPDATE_ORG_UNIT, REVISION_COUNT) -VALUES('00000007', 'bond', 'james', 'bond', 'ACT', 'I', TIMESTAMP '1939-07-04 00:00:00.000000', 'BCDL', 'Wull.', NULL, '00000002', NULL, NULL, NULL, 'C v.', TIMESTAMP '1989-11-26 08:52:38.000000', 'CONV', 70, TIMESTAMP '2000-08-24 15:59:37.000000', 'PLOUSY', 70, 1); +VALUES('00000007', 'bond', 'james', 'bond', 'ACT', 'I', TIMESTAMP '1939-07-04 00:00:00.000000', 'BCSC', 'Wull', NULL, '00000002', NULL, NULL, NULL, 'C v.', TIMESTAMP '1989-11-26 08:52:38.000000', 'CONV', 70, TIMESTAMP '2000-08-24 15:59:37.000000', 'PLOUSY', 70, 1); -- 00000008 James Hunt HUnt From fde8f584ebfa828f09f99c8aa66719dbbf135fe1 Mon Sep 17 00:00:00 2001 From: Paulo Gomes da Cruz Junior Date: Wed, 17 Jan 2024 10:22:04 -0800 Subject: [PATCH 05/12] fix(FSADT1-1144): adding match for individuals --- .../controller/client/ClientController.java | 30 ++++++++++-- .../ClientAlreadyExistException.java | 10 +++- .../service/client/ClientLegacyService.java | 46 +++++++++++++++++-- .../gov/app/service/client/ClientService.java | 36 +++++++++++++-- .../ClientControllerIntegrationTest.java | 1 + frontend/src/composables/useFetch.ts | 5 ++ frontend/src/dto/CommonTypesDto.ts | 1 + .../src/helpers/ForestClientUserSession.ts | 1 + .../controller/ClientSearchController.java | 1 + 9 files changed, 118 insertions(+), 13 deletions(-) diff --git a/backend/src/main/java/ca/bc/gov/app/controller/client/ClientController.java b/backend/src/main/java/ca/bc/gov/app/controller/client/ClientController.java index 663b764f90..286fe895eb 100644 --- a/backend/src/main/java/ca/bc/gov/app/controller/client/ClientController.java +++ b/backend/src/main/java/ca/bc/gov/app/controller/client/ClientController.java @@ -1,5 +1,6 @@ package ca.bc.gov.app.controller.client; +import ca.bc.gov.app.ApplicationConstant; import ca.bc.gov.app.dto.bcregistry.ClientDetailsDto; import ca.bc.gov.app.dto.client.ClientLookUpDto; import ca.bc.gov.app.dto.client.CodeNameDto; @@ -8,6 +9,8 @@ import ca.bc.gov.app.service.client.ClientService; import java.time.LocalDate; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.text.WordUtils; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -15,6 +18,7 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; 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.ResponseStatus; @@ -25,13 +29,18 @@ @RestController @RequestMapping(value = "/api/clients", produces = MediaType.APPLICATION_JSON_VALUE) @RequiredArgsConstructor +@Slf4j public class ClientController { private final ClientService clientService; @GetMapping("/{clientNumber}") - public Mono getClientDetails(@PathVariable String clientNumber) { - return clientService.getClientDetails(clientNumber); + public Mono getClientDetails( + @PathVariable String clientNumber, + @RequestHeader(ApplicationConstant.USERID_HEADER) String userId, + @RequestHeader(name = ApplicationConstant.BUSINESSID_HEADER, defaultValue = StringUtils.EMPTY) String businessId + ) { + return clientService.getClientDetails(clientNumber,userId,businessId); } @GetMapping("/activeCountryCodes") @@ -108,10 +117,23 @@ public Mono findByIncorporationNumber( .switchIfEmpty(Mono.error(new NoClientDataFound(incorporationId))); } + @GetMapping(value = "/individual/{userId}") + public Mono findByIndividual( + @PathVariable String userId, + @RequestParam String lastName + ) { + log.info("Receiving request to search individual with id {} and last name {}", userId, lastName); + return clientService.findByIndividual(userId,lastName); + } + @PostMapping("/mail") @ResponseStatus(HttpStatus.ACCEPTED) - public Mono sendEmail(@RequestBody EmailRequestDto emailRequestDto) { - return clientService.triggerEmailDuplicatedClient(emailRequestDto); + public Mono sendEmail( + @RequestBody EmailRequestDto emailRequestDto, + @RequestHeader(ApplicationConstant.USERID_HEADER) String userId, + @RequestHeader(name = ApplicationConstant.BUSINESSID_HEADER, defaultValue = StringUtils.EMPTY) String businessId + ) { + return clientService.triggerEmailDuplicatedClient(emailRequestDto, userId, businessId); } } diff --git a/backend/src/main/java/ca/bc/gov/app/exception/ClientAlreadyExistException.java b/backend/src/main/java/ca/bc/gov/app/exception/ClientAlreadyExistException.java index 95f4e8f762..e9c4e83b34 100644 --- a/backend/src/main/java/ca/bc/gov/app/exception/ClientAlreadyExistException.java +++ b/backend/src/main/java/ca/bc/gov/app/exception/ClientAlreadyExistException.java @@ -22,5 +22,13 @@ public ClientAlreadyExistException( ) ); } - + + public ClientAlreadyExistException(String clientNumber) { + super(HttpStatus.CONFLICT, + String.format( + "Client already exists with the client number %s", + clientNumber + ) + ); + } } diff --git a/backend/src/main/java/ca/bc/gov/app/service/client/ClientLegacyService.java b/backend/src/main/java/ca/bc/gov/app/service/client/ClientLegacyService.java index 5a0e74f6c7..da702a38f8 100644 --- a/backend/src/main/java/ca/bc/gov/app/service/client/ClientLegacyService.java +++ b/backend/src/main/java/ca/bc/gov/app/service/client/ClientLegacyService.java @@ -4,6 +4,7 @@ import java.util.Map; import java.util.Optional; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import org.springframework.web.reactive.function.client.WebClient; @@ -20,21 +21,37 @@ public ClientLegacyService(@Qualifier("legacyApi") WebClient legacyApi) { } /** - * Searches for a list of {@link ForestClientDto} in the legacy API based on - * the given incorporation number and company name. + * Searches for a list of {@link ForestClientDto} in the legacy API based on the given + * incorporation number and company name. * * @param incorporationNumber the incorporation number to search for * @param companyName the company name to search for + * @param userId the id of the user making the request + * @param businessId the id of the business making the request in case of bceid * @return a Flux of ForestClientDto objects matching the search criteria */ - public Flux searchLegacy(String incorporationNumber, String companyName) { + public Flux searchLegacy( + String incorporationNumber, + String companyName, + String userId, + String businessId + ) { return legacyApi .get() .uri(builder -> builder .path("/search/incorporationOrName") - .queryParamIfPresent("incorporationNumber", Optional.ofNullable(incorporationNumber)) + .queryParamIfPresent("incorporationNumber", + Optional + .ofNullable(incorporationNumber) + .filter(StringUtils::isNotBlank) + .or( + () -> Optional + .ofNullable(userId) + .filter(StringUtils::isNotBlank) + ) + ) .queryParamIfPresent("companyName", Optional.ofNullable(companyName)) .build(Map.of()) ) @@ -43,4 +60,25 @@ public Flux searchLegacy(String incorporationNumber, String com dto -> log.info("Loading Legacy data for {} {} from legacy with client number {}", incorporationNumber, companyName, dto.clientNumber())); } + + public Flux searchIdAndLastName( + String id, + String lastName + ) { + return + legacyApi + .get() + .uri(builder -> + builder + .path("/search/idAndLastName") + .queryParam("clientId", id) + .queryParam("lastName", lastName) + .build(Map.of()) + ) + .exchangeToFlux(response -> response.bodyToFlux(ForestClientDto.class)) + .doOnNext( + dto -> log.info("Loading Legacy data for {} {} from legacy with client number {}", + id, lastName, dto.clientNumber()) + ); + } } diff --git a/backend/src/main/java/ca/bc/gov/app/service/client/ClientService.java b/backend/src/main/java/ca/bc/gov/app/service/client/ClientService.java index b278649a25..ba298b6153 100644 --- a/backend/src/main/java/ca/bc/gov/app/service/client/ClientService.java +++ b/backend/src/main/java/ca/bc/gov/app/service/client/ClientService.java @@ -168,7 +168,9 @@ public Flux listClientContactTypeCodes(LocalDate activeDate,int pag * @return a Mono that emits a ClientDetailsDto object representing the details of the client */ public Mono getClientDetails( - String clientNumber + String clientNumber, + String userId, + String businessId ) { log.info("Loading details for {}", clientNumber); return @@ -183,7 +185,12 @@ public Mono getClientDetails( ) .flatMap(document -> legacyService - .searchLegacy(document.business().identifier(), document.business().legalName()) + .searchLegacy( + document.business().identifier(), + document.business().legalName(), + userId, + businessId + ) .next() .filter(isMatchWith(document)) .doOnNext(legacy -> @@ -268,16 +275,37 @@ public Mono sendEmail(EmailRequestDto emailRequestDto) { * @param emailRequestDto The request data containing user and client details. * @return A {@link Mono} of {@link Void}. */ - public Mono triggerEmailDuplicatedClient(EmailRequestDto emailRequestDto) { + public Mono triggerEmailDuplicatedClient( + EmailRequestDto emailRequestDto, + String userId, + String businessId + ) { return legacyService - .searchLegacy(emailRequestDto.incorporation(), emailRequestDto.name()) + .searchLegacy( + emailRequestDto.incorporation(), + emailRequestDto.name(), + userId, + businessId + ) .next() .flatMap( triggerEmailDuplicatedClient(emailRequestDto.email(), emailRequestDto.userName())) .then(); } + + public Mono findByIndividual(String userId, String lastName) { + return legacyService + .searchIdAndLastName(userId, lastName) + .doOnNext(legacy -> log.info("Found legacy entry for {} {}", userId, lastName)) + //If we have result, we return a Mono.error with the exception, otherwise return a Mono.empty + .next() + .flatMap(legacy -> Mono + .error(new ClientAlreadyExistException(legacy.clientNumber())) + ); + } + private Function> buildDetails() { return document -> buildAddress(document, diff --git a/backend/src/test/java/ca/bc/gov/app/controller/client/ClientControllerIntegrationTest.java b/backend/src/test/java/ca/bc/gov/app/controller/client/ClientControllerIntegrationTest.java index 11f8a08d13..a1b48655f6 100644 --- a/backend/src/test/java/ca/bc/gov/app/controller/client/ClientControllerIntegrationTest.java +++ b/backend/src/test/java/ca/bc/gov/app/controller/client/ClientControllerIntegrationTest.java @@ -434,6 +434,7 @@ void shouldSendEmail() { .post() .uri("/api/clients/mail") .body(Mono.just(TestConstants.EMAIL_REQUEST), EmailRequestDto.class) + .header(ApplicationConstant.USERID_HEADER, "testUserId") .exchange() .expectStatus().isAccepted() .expectBody().isEmpty(); diff --git a/frontend/src/composables/useFetch.ts b/frontend/src/composables/useFetch.ts index 3f7cb7eed2..d386ec316a 100644 --- a/frontend/src/composables/useFetch.ts +++ b/frontend/src/composables/useFetch.ts @@ -2,6 +2,7 @@ import { ref, type Ref } from "vue"; import axios, { type AxiosError } from "axios"; import { backendUrl, frontendUrl } from "@/CoreConstants"; import { useEventBus } from "@vueuse/core"; +import ForestClientUserSession from "@/helpers/ForestClientUserSession"; import type { ValidationMessageType } from "@/dto/CommonTypesDto"; const notificationBus = useEventBus( @@ -43,6 +44,10 @@ export const useFetchTo = ( "Content-Type": "application/json", "Access-Control-Allow-Origin": frontendUrl, ...config.headers, + "x-user-id": ForestClientUserSession.user?.userId ?? "", + "x-user-businessid": ForestClientUserSession.user?.businessId ?? "", + "x-user-email": ForestClientUserSession.user?.email ?? "", + "x-user-name": `${ForestClientUserSession.user?.firstName} ${ForestClientUserSession.user?.lastName}`, }, }; diff --git a/frontend/src/dto/CommonTypesDto.ts b/frontend/src/dto/CommonTypesDto.ts index af07cf8609..f9cc2f7ccd 100644 --- a/frontend/src/dto/CommonTypesDto.ts +++ b/frontend/src/dto/CommonTypesDto.ts @@ -78,6 +78,7 @@ export interface Submitter { email: string; provider: string; userId: string | undefined; + businessId: string | undefined; firstName: string; lastName: string; businessName: string; diff --git a/frontend/src/helpers/ForestClientUserSession.ts b/frontend/src/helpers/ForestClientUserSession.ts index 40a8004467..79d6181c0a 100644 --- a/frontend/src/helpers/ForestClientUserSession.ts +++ b/frontend/src/helpers/ForestClientUserSession.ts @@ -84,6 +84,7 @@ class ForestClientUserSession implements SessionProperties { name: toTitleCase(parsedUser["custom:idp_display_name"]), provider: provider, userId: `${provider}\\${parsedUser["custom:idp_username"] ?? parsedUser["custom:idp_user_id"]}`, + businessId: parsedUser["custom:idp_business_id"] ?? "", birthdate: parsedUser["birthdate"], address: { locationName: "", diff --git a/legacy/src/main/java/ca/bc/gov/app/controller/ClientSearchController.java b/legacy/src/main/java/ca/bc/gov/app/controller/ClientSearchController.java index 7712f07ad0..858841c4dc 100644 --- a/legacy/src/main/java/ca/bc/gov/app/controller/ClientSearchController.java +++ b/legacy/src/main/java/ca/bc/gov/app/controller/ClientSearchController.java @@ -50,6 +50,7 @@ public Flux findByIdAndLastName( @RequestParam String clientId, @RequestParam String lastName ) { + log.info("Receiving request to search by ID {} and Last Name {}", clientId, lastName); return service.findByIdAndLastName(clientId, lastName); } From 21409b49a6dccd51b6b9c004a77f812455145c11 Mon Sep 17 00:00:00 2001 From: Paulo Gomes da Cruz Junior Date: Wed, 17 Jan 2024 11:02:40 -0800 Subject: [PATCH 06/12] test(FSADT1-1144): adding test cases --- .../ClientControllerIntegrationTest.java | 45 ++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/backend/src/test/java/ca/bc/gov/app/controller/client/ClientControllerIntegrationTest.java b/backend/src/test/java/ca/bc/gov/app/controller/client/ClientControllerIntegrationTest.java index a1b48655f6..a5d28fb66a 100644 --- a/backend/src/test/java/ca/bc/gov/app/controller/client/ClientControllerIntegrationTest.java +++ b/backend/src/test/java/ca/bc/gov/app/controller/client/ClientControllerIntegrationTest.java @@ -32,6 +32,7 @@ import org.junit.jupiter.params.provider.MethodSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; import org.springframework.http.MediaType; import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.web.util.UriBuilder; @@ -443,7 +444,7 @@ void shouldSendEmail() { @Test @DisplayName("get country by code") - void shoulGgetCountryByCode() { + void shouldGetCountryByCode() { client .get() @@ -455,6 +456,48 @@ void shoulGgetCountryByCode() { } + @Test + @DisplayName("check for individual conflicts") + void shouldCheckIndividual() { + + legacyStub + .stubFor( + get(urlPathEqualTo("/search/idAndLastName")) + .withQueryParam("clientId",equalTo("123456")) + .withQueryParam("lastName", equalTo("Doe")) + .willReturn(okJson(TestConstants.LEGACY_OK)) + ); + + client + .get() + .uri("/api/clients/individual/{userId}?lastName=Doe", Map.of("userId", "123456")) + .exchange() + .expectStatus().isEqualTo(HttpStatus.CONFLICT) + .expectBody(String.class) + .isEqualTo("Client already exists with the client number 00000002"); + } + + @Test + @DisplayName("check for individual conflicts and get none") + void shouldCheckIndividualWithoutConflict() { + + legacyStub + .stubFor( + get(urlPathEqualTo("/search/idAndLastName")) + .withQueryParam("clientId",equalTo("123456")) + .withQueryParam("lastName", equalTo("Doe")) + .willReturn(okJson("[]")) + ); + + client + .get() + .uri("/api/clients/individual/{userId}?lastName=Doe", Map.of("userId", "123456")) + .exchange() + .expectStatus().isOk() + .expectBody() + .isEmpty(); + } + private static Stream clientDetailing() { return Stream.of( From ac1caf087e9ab56ab147cd26ab0160fba02a3365 Mon Sep 17 00:00:00 2001 From: Paulo Gomes da Cruz Junior Date: Wed, 17 Jan 2024 12:02:54 -0800 Subject: [PATCH 07/12] fix(FSADT1-1144): preventing bcsc when 100% match - 100% match happens using user id + last name --- frontend/src/pages/FormBCSCPage.vue | 16 ++++- frontend/stub/mappings/backend.json | 91 +++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 2 deletions(-) diff --git a/frontend/src/pages/FormBCSCPage.vue b/frontend/src/pages/FormBCSCPage.vue index 55ed0103c1..3b467acecf 100644 --- a/frontend/src/pages/FormBCSCPage.vue +++ b/frontend/src/pages/FormBCSCPage.vue @@ -1,6 +1,6 @@