diff --git a/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/BcRegistryAlternateNameDto.java b/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/BcRegistryAlternateNameDto.java new file mode 100644 index 0000000000..3622632759 --- /dev/null +++ b/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/BcRegistryAlternateNameDto.java @@ -0,0 +1,19 @@ +package ca.bc.gov.app.dto.bcregistry; + + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.time.LocalDate; +import java.time.ZonedDateTime; +import lombok.With; + +@With +@JsonIgnoreProperties(ignoreUnknown = true) +public record BcRegistryAlternateNameDto( + String entityType, + String identifier, + String name, + ZonedDateTime registeredDate, + LocalDate startDate +) { + +} diff --git a/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/BcRegistryBusinessDto.java b/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/BcRegistryBusinessDto.java index a10a08795c..5da2f5f794 100644 --- a/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/BcRegistryBusinessDto.java +++ b/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/BcRegistryBusinessDto.java @@ -1,11 +1,15 @@ package ca.bc.gov.app.dto.bcregistry; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.util.Comparator; +import java.util.List; import lombok.With; +import org.springframework.util.CollectionUtils; @With @JsonIgnoreProperties(ignoreUnknown = true) public record BcRegistryBusinessDto( + List alternateNames, Boolean goodStanding, Boolean hasCorrections, Boolean hasCourtOrders, @@ -15,4 +19,21 @@ public record BcRegistryBusinessDto( String legalType, String state ) { + + public String getResolvedLegalName() { + + List names = + CollectionUtils.isEmpty(alternateNames) + ? List.of() + : alternateNames; + + return + names + .stream() + .sorted(Comparator.comparing(BcRegistryAlternateNameDto::registeredDate)) + .map(BcRegistryAlternateNameDto::name) + .findFirst() + .orElse(legalName); + } + } diff --git a/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/BcRegistryDocumentDto.java b/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/BcRegistryDocumentDto.java index 2570639088..e1a50686d2 100644 --- a/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/BcRegistryDocumentDto.java +++ b/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/BcRegistryDocumentDto.java @@ -1,11 +1,7 @@ package ca.bc.gov.app.dto.bcregistry; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import java.util.HashMap; -import java.util.HashSet; import java.util.List; -import java.util.Map; -import java.util.Set; import lombok.With; @With @@ -16,41 +12,9 @@ public record BcRegistryDocumentDto( List parties ) { - /** - * Returns a mapping of addresses to sets of parties associated with those addresses. If the - * offices object is valid, adds all of its addresses to the mapping with an empty set of parties. - * For each valid party, adds it to the set of parties associated with its mailing or delivery - * address in the mapping. - * - * @return a mapping of addresses to sets of parties associated with those addresses - */ - public Map> matchOfficesParties() { - - Map> results = new HashMap<>(); - - // If offices exist and are valid, add all their addresses to the results map - if (offices != null && offices.isValid()) { - offices.addresses().forEach(address -> results.put(address, new HashSet<>())); - } - - // For each party, if it's valid and has a mailing or delivery address, - // add it to the set of parties associated with that address in the results map - for (BcRegistryPartyDto party : parties) { - if (!party.isValid()) { - continue; - } - - BcRegistryAddressDto mailingAddress = party.mailingAddress(); - if (mailingAddress != null) { - results.computeIfAbsent(mailingAddress, key -> new HashSet<>()).add(party); - } - - BcRegistryAddressDto deliveryAddress = party.deliveryAddress(); - if (deliveryAddress != null) { - results.computeIfAbsent(deliveryAddress, key -> new HashSet<>()).add(party); - } - } - - return results; + public boolean isOwnedByPerson() { + List localParties = parties == null ? List.of() : parties; + return localParties.stream().anyMatch(BcRegistryPartyDto::isPerson); } + } \ No newline at end of file diff --git a/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/BcRegistryFacetPartyDto.java b/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/BcRegistryFacetPartyDto.java new file mode 100644 index 0000000000..bf931a9fb5 --- /dev/null +++ b/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/BcRegistryFacetPartyDto.java @@ -0,0 +1,15 @@ +package ca.bc.gov.app.dto.bcregistry; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.util.List; +import lombok.With; + +@With +@JsonIgnoreProperties(ignoreUnknown = true) +public record BcRegistryFacetPartyDto( + String partyName, + List partyRoles, + String partyType +) { + +} diff --git a/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/BcRegistryFacetRequestBodyDto.java b/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/BcRegistryFacetRequestBodyDto.java new file mode 100644 index 0000000000..d70ba6b7a1 --- /dev/null +++ b/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/BcRegistryFacetRequestBodyDto.java @@ -0,0 +1,17 @@ +package ca.bc.gov.app.dto.bcregistry; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.util.List; +import java.util.Map; +import lombok.With; + +@With +@JsonIgnoreProperties(ignoreUnknown = true) +public record BcRegistryFacetRequestBodyDto( + BcRegistryFacetRequestQueryDto query, + Map> categories, + int rows, + int start +) { + +} diff --git a/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/BcRegistryFacetRequestQueryDto.java b/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/BcRegistryFacetRequestQueryDto.java new file mode 100644 index 0000000000..32e004df67 --- /dev/null +++ b/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/BcRegistryFacetRequestQueryDto.java @@ -0,0 +1,16 @@ +package ca.bc.gov.app.dto.bcregistry; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.With; + +@With +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public record BcRegistryFacetRequestQueryDto( + String value, + String name, + String identifier +) { + +} diff --git a/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/BcRegistryFacetSearchResultEntryDto.java b/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/BcRegistryFacetSearchResultEntryDto.java index bb56ee45c9..25a5dd23e8 100644 --- a/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/BcRegistryFacetSearchResultEntryDto.java +++ b/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/BcRegistryFacetSearchResultEntryDto.java @@ -1,6 +1,7 @@ package ca.bc.gov.app.dto.bcregistry; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.util.List; import lombok.With; @With @@ -11,6 +12,8 @@ public record BcRegistryFacetSearchResultEntryDto( String legalType, String name, String status, - Boolean goodStanding + Boolean goodStanding, + List parties ) { + } diff --git a/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/ClientDetailsDto.java b/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/ClientDetailsDto.java index 120ead3360..004243a69f 100644 --- a/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/ClientDetailsDto.java +++ b/backend/src/main/java/ca/bc/gov/app/dto/bcregistry/ClientDetailsDto.java @@ -15,7 +15,8 @@ public record ClientDetailsDto( Boolean goodStanding, String clientType, List addresses, - List contacts + List contacts, + boolean isOwnedByPerson ) { } diff --git a/backend/src/main/java/ca/bc/gov/app/service/bcregistry/BcRegistryService.java b/backend/src/main/java/ca/bc/gov/app/service/bcregistry/BcRegistryService.java index f8c7e2f3a5..2c6e8bccf8 100644 --- a/backend/src/main/java/ca/bc/gov/app/service/bcregistry/BcRegistryService.java +++ b/backend/src/main/java/ca/bc/gov/app/service/bcregistry/BcRegistryService.java @@ -3,27 +3,42 @@ import static ca.bc.gov.app.ApplicationConstant.BUSINESS_SUMMARY_FILING_HISTORY; import ca.bc.gov.app.dto.bcregistry.BcRegistryAddressDto; +import ca.bc.gov.app.dto.bcregistry.BcRegistryAlternateNameDto; import ca.bc.gov.app.dto.bcregistry.BcRegistryBusinessAdressesDto; import ca.bc.gov.app.dto.bcregistry.BcRegistryBusinessDto; import ca.bc.gov.app.dto.bcregistry.BcRegistryDocumentDto; import ca.bc.gov.app.dto.bcregistry.BcRegistryDocumentRequestDocumentDto; import ca.bc.gov.app.dto.bcregistry.BcRegistryDocumentRequestResponseDto; import ca.bc.gov.app.dto.bcregistry.BcRegistryExceptionMessageDto; +import ca.bc.gov.app.dto.bcregistry.BcRegistryFacetPartyDto; +import ca.bc.gov.app.dto.bcregistry.BcRegistryFacetRequestBodyDto; +import ca.bc.gov.app.dto.bcregistry.BcRegistryFacetRequestQueryDto; import ca.bc.gov.app.dto.bcregistry.BcRegistryFacetResponseDto; import ca.bc.gov.app.dto.bcregistry.BcRegistryFacetSearchResultEntryDto; import ca.bc.gov.app.dto.bcregistry.BcRegistryFacetSearchResultsDto; +import ca.bc.gov.app.dto.bcregistry.BcRegistryOfficerDto; import ca.bc.gov.app.dto.bcregistry.BcRegistryOfficesDto; +import ca.bc.gov.app.dto.bcregistry.BcRegistryPartyDto; +import ca.bc.gov.app.dto.bcregistry.BcRegistryRoleDto; +import ca.bc.gov.app.exception.BadRequestException; import ca.bc.gov.app.exception.InvalidAccessTokenException; import ca.bc.gov.app.exception.NoClientDataFound; +import ca.bc.gov.app.exception.UnexpectedErrorException; +import ca.bc.gov.app.util.ClientMapper; import io.micrometer.observation.ObservationRegistry; import io.micrometer.observation.annotation.Observed; +import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; +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.http.HttpStatusCode; import org.springframework.http.MediaType; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; import org.springframework.web.reactive.function.BodyInserters; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.observability.micrometer.Micrometer; @@ -46,7 +61,6 @@ public BcRegistryService( this.registry = registry; } - /** * Searches the BC Registry API for {@link BcRegistryFacetSearchResultEntryDto} instances matching * the given value. @@ -60,30 +74,41 @@ public Flux searchByFacets(String value) { log.info("Searching BC Registry for {}", value); return bcRegistryApi - .get() - .uri(uriBuilder -> - uriBuilder - .path("/registry-search/api/v1/businesses/search/facets") - .queryParam("query", String.format("value:%s", value)) - .queryParam("start", "0") - .queryParam("rows", "100") - .queryParam("category", "status:Active") - .build(Map.of()) + .post() + .uri("/registry-search/api/v2/search/businesses") + .body(BodyInserters.fromValue( + new BcRegistryFacetRequestBodyDto( + new BcRegistryFacetRequestQueryDto(value, value, null), + Map.of("status", List.of("ACTIVE")), + 100, + 0 + ) + ) ) .accept(MediaType.APPLICATION_JSON) .retrieve() // handle different HTTP error codes - .onStatus( - statusCode -> statusCode.isSameCodeAs(HttpStatusCode.valueOf(404)), - exception -> Mono.error(new NoClientDataFound(value)) - ) .onStatus( statusCode -> statusCode.isSameCodeAs(HttpStatusCode.valueOf(401)), exception -> Mono.error(new InvalidAccessTokenException()) ) .onStatus( statusCode -> statusCode.isSameCodeAs(HttpStatusCode.valueOf(400)), - exception -> Mono.error(new InvalidAccessTokenException()) + exception -> exception + .bodyToMono(BcRegistryExceptionMessageDto.class) + .flatMap(ex -> Mono.error(new BadRequestException(ex.errorMessage()))) + ) + .onStatus( + HttpStatusCode::isError, + exception -> exception + .bodyToMono(BcRegistryExceptionMessageDto.class) + .flatMap(ex -> Mono.error( + new UnexpectedErrorException( + exception.statusCode().value(), + ex.errorMessage() + ) + ) + ) ) .bodyToMono(BcRegistryFacetResponseDto.class) .name("request.bcregistry") @@ -92,7 +117,9 @@ public Flux searchByFacets(String value) { .map(BcRegistryFacetResponseDto::searchResults) .flatMapIterable(BcRegistryFacetSearchResultsDto::results) .filter(entry -> entry.status().equalsIgnoreCase("active")) - .doOnNext(content -> log.info("Found entry on BC Registry [{}] {}", content.identifier(),content.name())); + .doOnNext( + content -> log.info("Found entry on BC Registry [{}] {}", content.identifier(), + content.name())); } /** @@ -140,6 +167,18 @@ public Flux requestDocumentData(String value) { .flatMap(message -> Mono.error(new NoClientDataFound(value))) ) + .onStatus( + HttpStatusCode::isError, + exception -> exception + .bodyToMono(BcRegistryExceptionMessageDto.class) + .flatMap(ex -> Mono.error( + new UnexpectedErrorException( + exception.statusCode().value(), + ex.errorMessage() + ) + ) + ) + ) .bodyToMono(BcRegistryDocumentRequestResponseDto.class) .name("request.bcregistry") .tag("kind", "docreq") @@ -151,48 +190,7 @@ public Flux requestDocumentData(String value) { .flatMap(documentKey -> getDocumentData(value, documentKey)) //This will try to load the standing and business data for entries with no documents .onErrorResume(NoClientDataFound.class, exception -> - searchByFacets(value) - .next() - .map(facet -> new BcRegistryBusinessDto( - facet.goodStanding(), - false, - false, - false, - facet.identifier(), - facet.name(), - facet.legalType(), - facet.status() - ) - ) - .map(business -> new BcRegistryDocumentDto( - business, - new BcRegistryOfficesDto( - new BcRegistryBusinessAdressesDto( - new BcRegistryAddressDto( - null, - null, - null, - null, - null, - null, - null, - null - ), - new BcRegistryAddressDto( - null, - null, - null, - null, - null, - null, - null, - null - ) - ) - ), - List.of() - ) - ) + searchByFacets(value).next().map(this::buildDocumentData) ); } @@ -226,4 +224,92 @@ private Mono getDocumentData(String identifier, String do document -> log.info("Document loaded for {} {} as {}", identifier, documentKey, document.business().legalName())); } + + private BcRegistryDocumentDto buildDocumentData( + BcRegistryFacetSearchResultEntryDto facet + ) { + // We have no address data in the facet, so we'll just create empty address objects + BcRegistryAddressDto address = + new BcRegistryAddressDto(null, null, null, null, null, null, null, null); + + // We build the alternate name that's being used down the line + BcRegistryAlternateNameDto alternateName = + new BcRegistryAlternateNameDto( + facet.legalType(), + facet.identifier(), + facet.name(), + null, + null + ); + + // We can have the parties value, so we will build the parties list + List parties = new ArrayList<>(); + + // and we fill it with the parties from facet + if (!CollectionUtils.isEmpty(facet.parties())) { + facet + .parties() + .stream() + .map(this::buildBcRegistryPartyDto) + .filter(Objects::nonNull) + .forEachOrdered(parties::add); + } + + BcRegistryBusinessDto business = + new BcRegistryBusinessDto( + List.of(alternateName), + facet.goodStanding(), + false, + false, + false, + facet.identifier(), + facet.name(), + facet.legalType(), + facet.status() + ); + + return + new BcRegistryDocumentDto( + business, + new BcRegistryOfficesDto( + new BcRegistryBusinessAdressesDto(address, address) + ), + parties + ); + + } + + private BcRegistryPartyDto buildBcRegistryPartyDto(BcRegistryFacetPartyDto party) { + + if (StringUtils.isEmpty(party.partyType()) || !party.partyType().equalsIgnoreCase("person")) { + return null; + } + + List roles = + Optional + .ofNullable(party.partyRoles()) + .map(partyRoles -> + partyRoles + .stream() + .map(StringUtils::capitalize) + .map(role -> new BcRegistryRoleDto(null, null, role)) + .toList() + ) + .orElse(List.of()); + + Map naming = ClientMapper.parseName(party.partyName(), "BCREGISTRY"); + + return new BcRegistryPartyDto( + null, + null, + new BcRegistryOfficerDto( + null, + naming.get("firstName"), + naming.get("lastName"), + null, + party.partyType() + ), + roles + ); + } } 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 b67705cf8f..e31a9d4939 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 @@ -228,14 +228,14 @@ public Mono getClientDetails( .doOnNext(document -> log.info("Searching on Oracle legacy db for {} {}", document.business().identifier(), - document.business().legalName() + document.business().getResolvedLegalName() ) ) .flatMap(document -> legacyService .searchLegacy( document.business().identifier(), - document.business().legalName(), + document.business().getResolvedLegalName(), userId, businessId ) @@ -244,7 +244,7 @@ public Mono getClientDetails( .doOnNext(legacy -> log.info("Found legacy entry for {} {}", document.business().identifier(), - document.business().legalName() + document.business().getResolvedLegalName() ) ) .flatMap(legacy -> Mono @@ -252,13 +252,14 @@ public Mono getClientDetails( new ClientAlreadyExistException( legacy.clientNumber(), document.business().identifier(), - document.business().legalName()) + document.business().getResolvedLegalName()) ) ) .defaultIfEmpty(document) .doOnNext(value -> log.info("No entry found on legacy for {} {}", - document.business().identifier(), document.business().legalName() + document.business().identifier(), + document.business().getResolvedLegalName() ) ) ) @@ -385,12 +386,13 @@ private Function> buildDetails() { return document -> buildAddress( document, - buildSimpleClientDetails(document.business()) + buildSimpleClientDetails(document.business(),document.isOwnedByPerson()) ); } private ClientDetailsDto buildSimpleClientDetails( - BcRegistryBusinessDto businessDto + BcRegistryBusinessDto businessDto, + boolean isOwnedByPerson ) { if (businessDto == null) { @@ -400,19 +402,21 @@ private ClientDetailsDto buildSimpleClientDetails( false, "", List.of(), - List.of() + List.of(), + isOwnedByPerson ); } log.info("Building simple client details for {} with standing {}", businessDto.identifier(), businessDto.goodStanding()); return new ClientDetailsDto( - businessDto.legalName(), + businessDto.getResolvedLegalName(), businessDto.identifier(), businessDto.goodStanding(), businessDto.legalType(), List.of(), - List.of() + List.of(), + isOwnedByPerson ); } diff --git a/backend/src/main/java/ca/bc/gov/app/service/client/matches/RegisteredStepMatcher.java b/backend/src/main/java/ca/bc/gov/app/service/client/matches/RegisteredStepMatcher.java index dd9ebc4dc5..b664040003 100644 --- a/backend/src/main/java/ca/bc/gov/app/service/client/matches/RegisteredStepMatcher.java +++ b/backend/src/main/java/ca/bc/gov/app/service/client/matches/RegisteredStepMatcher.java @@ -9,6 +9,7 @@ import java.util.Map; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.springframework.stereotype.Component; import reactor.core.publisher.Flux; @@ -70,7 +71,16 @@ public Mono matchStep(ClientSubmissionDto dto) { Flux individualFuzzyMatch = Mono .just(dto.businessInformation()) + //If it's a Registered Sole Proprietorship .filter(businessInformation -> businessInformation.clientType().equals("RSP")) + //And we have First and Last name + .filter(businessInformation -> !StringUtils.isAllBlank( + businessInformation.firstName(), + businessInformation.lastName() + ) + ) + //And we have a birthdate + .filter(businessInformation -> businessInformation.birthdate() != null) .flatMapMany(businessInformation -> legacyService.searchIndividual( businessInformation.firstName(), @@ -126,7 +136,7 @@ public Mono matchStep(ClientSubmissionDto dto) { legacyService .searchGeneric( "doingBusinessAs", - "dbaName", + "dbaName", dto.businessInformation().doingBusinessAs() ).doOnNext(client -> log.info("Match found for doing business as fuzzy match: {}", client.clientNumber()) diff --git a/backend/src/main/java/ca/bc/gov/app/service/opendata/OpenDataService.java b/backend/src/main/java/ca/bc/gov/app/service/opendata/OpenDataService.java index 117e5224ee..712c54b346 100644 --- a/backend/src/main/java/ca/bc/gov/app/service/opendata/OpenDataService.java +++ b/backend/src/main/java/ca/bc/gov/app/service/opendata/OpenDataService.java @@ -73,7 +73,8 @@ private Mono convertToDto(Feature openDataFeature) { true, openDataFeature.properties().getFirstNationType().name(), addressDto.isValid() ? List.of(addressDto) : List.of(), - List.of() + List.of(), + false ); }); } diff --git a/backend/src/main/java/ca/bc/gov/app/validator/business/BusinessInformationBusinessRegisteredNumberValidator.java b/backend/src/main/java/ca/bc/gov/app/validator/business/BusinessInformationBusinessRegisteredNumberValidator.java index cbbb9f83b3..5ef18fc108 100644 --- a/backend/src/main/java/ca/bc/gov/app/validator/business/BusinessInformationBusinessRegisteredNumberValidator.java +++ b/backend/src/main/java/ca/bc/gov/app/validator/business/BusinessInformationBusinessRegisteredNumberValidator.java @@ -3,6 +3,7 @@ import static ca.bc.gov.app.util.ClientValidationUtils.fieldIsMissingErrorMessage; import ca.bc.gov.app.dto.ValidationError; +import ca.bc.gov.app.dto.bcregistry.BcRegistryDocumentDto; import ca.bc.gov.app.dto.client.BusinessTypeEnum; import ca.bc.gov.app.dto.client.ClientBusinessInformationDto; import ca.bc.gov.app.dto.client.LegalTypeEnum; @@ -10,6 +11,8 @@ import ca.bc.gov.app.service.bcregistry.BcRegistryService; import ca.bc.gov.app.validator.ForestClientValidator; import io.micrometer.observation.annotation.Observed; +import java.util.function.Function; +import java.util.stream.Stream; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -61,12 +64,7 @@ public Mono validate(ClientBusinessInformationDto target, Integ return bcRegistryService .requestDocumentData(target.registrationNumber()) - .map(bcRegistryBusinessDto -> - Boolean.FALSE.equals(bcRegistryBusinessDto.business().goodStanding()) - ? new ValidationError(fieldName, - "Company is not in goodStanding in BC Registry") - : new ValidationError("", "") - ) + .map(checkSoleProprietor(fieldName)) .onErrorReturn(ResponseStatusException.class, new ValidationError(fieldName, "Incorporation Number was not found in BC Registry") @@ -82,4 +80,40 @@ public Mono validate(ClientBusinessInformationDto target, Integ return Mono.empty(); } + private Function checkSoleProprietor( + String fieldName) { + return bcRegistryBusinessDto -> + Stream.of( + checkStanding(fieldName), + checkSoleProprietorOwner(fieldName) + ) + .map(f -> f.apply(bcRegistryBusinessDto)) + .filter(ValidationError::isValid) + .findFirst() + .orElse(new ValidationError("", "")); + + } + + private Function checkStanding( + String fieldName) { + return bcRegistryBusinessDto -> + Boolean.FALSE.equals(bcRegistryBusinessDto.business().goodStanding()) + ? new ValidationError(fieldName, + "Company is not in goodStanding in BC Registry") + : new ValidationError("", ""); + } + + private Function checkSoleProprietorOwner( + String fieldName) { + return bcRegistryBusinessDto -> + Boolean.FALSE.equals(bcRegistryBusinessDto.isOwnedByPerson()) + ? new ValidationError( + fieldName, + String.format("%s sole proprietor is not owned by a person", + bcRegistryBusinessDto.business().getResolvedLegalName() + ) + ) + : new ValidationError("", ""); + } + } diff --git a/backend/src/test/java/ca/bc/gov/app/BcRegistryTestConstants.java b/backend/src/test/java/ca/bc/gov/app/BcRegistryTestConstants.java new file mode 100644 index 0000000000..36f9fd4477 --- /dev/null +++ b/backend/src/test/java/ca/bc/gov/app/BcRegistryTestConstants.java @@ -0,0 +1,644 @@ +package ca.bc.gov.app; + +import ca.bc.gov.app.dto.bcregistry.BcRegistryAddressDto; +import ca.bc.gov.app.dto.bcregistry.BcRegistryAlternateNameDto; +import ca.bc.gov.app.dto.bcregistry.BcRegistryBusinessAdressesDto; +import ca.bc.gov.app.dto.bcregistry.BcRegistryBusinessDto; +import ca.bc.gov.app.dto.bcregistry.BcRegistryDocumentDto; +import ca.bc.gov.app.dto.bcregistry.BcRegistryOfficerDto; +import ca.bc.gov.app.dto.bcregistry.BcRegistryOfficesDto; +import ca.bc.gov.app.dto.bcregistry.BcRegistryPartyDto; +import ca.bc.gov.app.dto.bcregistry.BcRegistryRoleDto; +import java.time.LocalDate; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.List; +import org.apache.commons.lang3.StringUtils; + +public class BcRegistryTestConstants { + + public static final String NO_DATA = """ + {}"""; + + public static final String BCREG_DOC_REQ = """ + { + "documentAccessRequest":{ + "documents":[ + {"type":"BUSINESS_SUMMARY_FILING_HISTORY"} + ] + } + }"""; + + public static final String BCREG_DOC_REQ_RES = """ + { + "businessIdentifier": "AA0000001", + "documents": [ + { + "documentKey": "aa0a00a0a", + "documentType": "BUSINESS_SUMMARY_FILING_HISTORY", + "id": 18315 + } + ] + }"""; + + public static final String BCREG_DOC_REQ_FAIL = """ + { + "errorMessage": "API backend third party service error.", + "rootCause": "details:[],message:Business not found. " + }"""; + + + public static final String BCREG_FACET_FAIL = """ + { + "errorMessage": "API backend third party service error.", + "rootCause": "details:[Invalid payload:Expected an object for 'query'.],message:Errors processing request. " + }"""; + + public static final String BCREG_FACET_500 = """ + { + "errorMessage": "API unexpected error. If error persists, contact API support.", + "rootCause": "fault:faultstring:Execution of ServiceCallout SC-Request-JWT failed. Reason: timeout occurred in SC-Request-JWT,detail:errorcode:steps.servicecallout.ExecutionFailed" + }"""; + + public static final String BCREG_FACET_401 = """ + { + "errorMessage": "API security error: API key check failed.", + "rootCause": "fault:faultstring:Invalid ApiKey,detail:errorcode:oauth.v2.InvalidApiKey" + }"""; + + public static final String BCREG_FACET_EMPTY = """ + { + "searchResults": { + "results": [], + "totalResults": 0 + } + }"""; + + public static final String BCREG_RESPONSE_ANY = """ + { + "name": "SAMPLE COMPANY", + "id": "AA0000001", + "goodStanding": true, + "addresses": [], + "contacts": [] + }"""; + + public static final String BCREG_FACET_ANY = """ + { + "searchResults": { + "results": [ + { + "bn": "100000000000001", + "goodStanding": true, + "identifier": "C0123456", + "legalType": "C", + "name": "EXAMPLE COMPANY LTD.", + "score": 57.321865, + "status": "ACTIVE" + } + ], + "totalResults": 1 + } + }"""; + + public static final BcRegistryDocumentDto BCREG_DOCOBJ_ANY = new BcRegistryDocumentDto( + new BcRegistryBusinessDto( + List.of( + new BcRegistryAlternateNameDto( + "C", + "C0123456", + "EXAMPLE COMPANY LTD.", + null, + null + ) + ), + true, + false, + false, + false, + "C0123456", + "EXAMPLE COMPANY LTD.", + "C", + "ACTIVE" + ), + new BcRegistryOfficesDto( + new BcRegistryBusinessAdressesDto( + new BcRegistryAddressDto(null, null, null, null, null, null, null, null), + new BcRegistryAddressDto(null, null, null, null, null, null, null, null) + ) + ), + List.of() + ); + + public static final String BCREG_FACET_SP_ORG = """ + { + "searchResults": { + "results": [ + { + "bn": "100000000000002", + "identifier": "FM0123456", + "legalType": "SP", + "name": "EXAMPLE SOLE PROPRIETORSHIP", + "parties": [ + { + "partyName": "EXAMPLE COMPANY LTD.", + "partyRoles": [ + "proprietor" + ], + "partyType": "organization", + "score": 0.0 + } + ], + "score": 56.05646, + "status": "ACTIVE" + } + ], + "totalResults": 1 + } + }"""; + + public static final String BCREG_DOC_SP_ORG = """ + { + "business": { + "alternateNames": [ + { + "entityType": "SP", + "identifier": "FM0123456", + "name": "EXAMPLE SOLE PROPRIETORSHIP", + "registeredDate": "1985-07-23T07:00:00+00:00", + "startDate": null + } + ], + "goodStanding": true, + "hasCorrections": false, + "hasCourtOrders": false, + "hasRestrictions": false, + "identifier": "FM0123456", + "legalName": "EXAMPLE COMPANY LTD.", + "legalType": "SP", + "state": "ACTIVE" + }, + "offices": { + "message": "FM0123456 address not found" + }, + "parties": [ + { + "officer": { + "email": "", + "identifier": "BC0123456", + "organizationName": "EXAMPLE COMPANY LTD.", + "partyType": "organization" + }, + "roles": [ + { + "appointmentDate": "1985-07-23", + "cessationDate": null, + "roleType": "Proprietor" + } + ] + } + ] + }"""; + + public static final BcRegistryDocumentDto BCREG_DOCOBJ_SP_ORG = new BcRegistryDocumentDto( + new BcRegistryBusinessDto( + List.of( + new BcRegistryAlternateNameDto( + "SP", + "FM0123456", + "EXAMPLE SOLE PROPRIETORSHIP", + ZonedDateTime.of(1985, 7, 23, 7, 0, 0, 0, ZoneOffset.UTC), + null + ) + ), + true, + false, + false, + false, + "FM0123456", + "EXAMPLE COMPANY LTD.", + "SP", + "ACTIVE" + ), + new BcRegistryOfficesDto(null), + List.of( + new BcRegistryPartyDto( + null, null, + new BcRegistryOfficerDto( + StringUtils.EMPTY, + null, + null, + null, + "organization" + ), + List.of( + new BcRegistryRoleDto( + LocalDate.of(1985, 7, 23), + null, + "Proprietor" + ) + ) + ) + ) + ); + + public static final String BCREG_FACET_SP_PERSON = """ + { + "searchResults": { + "results": [ + { + "bn": "100000000000003", + "identifier": "FM0123210", + "legalType": "SP", + "name": "EXAMPLE SOLE PROPRIETORSHIP", + "parties": [ + { + "partyName": "JOHNATHAN WICK", + "partyRoles": [ + "proprietor" + ], + "partyType": "person", + "score": 0.0 + } + ], + "score": 56.05646, + "status": "ACTIVE" + } + ], + "totalResults": 1 + } + }"""; + + public static final String BCREG_DOC_SP_PERSON = """ + { + "business": { + "alternateNames": [ + { + "entityType": "SP", + "identifier": "FM0123210", + "name": "EXAMPLE SOLE PROPRIETORSHIP", + "registeredDate": "2009-11-30T08:00:00+00:00", + "startDate": "2009-10-01" + } + ], + "goodStanding": true, + "hasCorrections": false, + "hasCourtOrders": false, + "hasRestrictions": false, + "identifier": "FM0123210", + "legalName": "JOHNATHAN WICK", + "legalType": "SP", + "state": "ACTIVE" + }, + "offices": { + "businessOffice": { + "deliveryAddress": { + "addressCity": "Victoria", + "addressCountry": "Canada", + "addressRegion": "BC", + "addressType": "delivery", + "deliveryInstructions": "", + "postalCode": "V8T 5J9", + "streetAddress": "2975 Jutland Rd.", + "streetAddressAdditional": "" + }, + "mailingAddress": { + "addressCity": "Victoria", + "addressCountry": "Canada", + "addressRegion": "BC", + "addressType": "mailing", + "deliveryInstructions": "", + "postalCode": "V8T 5J9", + "streetAddress": "2975 Jutland Rd.", + "streetAddressAdditional": "" + } + } + }, + "parties": [ + { + "deliveryAddress": { + "addressCity": "Victoria", + "addressCountry": "Canada", + "addressRegion": "BC", + "deliveryInstructions": "", + "postalCode": "V8T 5J9", + "streetAddress": "2975 Jutland Rd.", + "streetAddressAdditional": "" + }, + "mailingAddress": { + "addressCity": "Victoria", + "addressCountry": "Canada", + "addressRegion": "BC", + "deliveryInstructions": "", + "postalCode": "V8T 5J9", + "streetAddress": "2975 Jutland Rd.", + "streetAddressAdditional": "" + }, + "officer": { + "email": "", + "firstName": "JOHNATHAN", + "lastName": "WICK", + "partyType": "person" + }, + "roles": [ + { + "appointmentDate": "2009-11-30", + "cessationDate": null, + "roleType": "Proprietor" + } + ] + } + ] + }"""; + + public static final BcRegistryDocumentDto BCREG_DOCOBJ_SP_PERSON = new BcRegistryDocumentDto( + new BcRegistryBusinessDto( + List.of( + new BcRegistryAlternateNameDto( + "SP", + "FM0123210", + "EXAMPLE SOLE PROPRIETORSHIP", + ZonedDateTime.of(2009, 11, 30, 8, 0, 0, 0, ZoneOffset.UTC), + LocalDate.of(2009, 10, 1) + ) + ), + true, + false, + false, + false, + "FM0123210", + "JOHNATHAN WICK", + "SP", + "ACTIVE" + ), + new BcRegistryOfficesDto( + new BcRegistryBusinessAdressesDto( + new BcRegistryAddressDto( + "Victoria", + "Canada", + "BC", + StringUtils.EMPTY, + "V8T 5J9", + "2975 Jutland Rd.", + StringUtils.EMPTY, + "mailing" + ), + new BcRegistryAddressDto( + "Victoria", + "Canada", + "BC", + StringUtils.EMPTY, + "V8T 5J9", + "2975 Jutland Rd.", + StringUtils.EMPTY, + "delivery" + ) + ) + ), + List.of( + new BcRegistryPartyDto( + new BcRegistryAddressDto( + "Victoria", + "Canada", + "BC", + StringUtils.EMPTY, + "V8T 5J9", + "2975 Jutland Rd.", + StringUtils.EMPTY, + null + ), + new BcRegistryAddressDto( + "Victoria", + "Canada", + "BC", + StringUtils.EMPTY, + "V8T 5J9", + "2975 Jutland Rd.", + StringUtils.EMPTY, + null + ), + new BcRegistryOfficerDto( + StringUtils.EMPTY, + "JOHNATHAN", + "WICK", + null, + "person" + ), + List.of( + new BcRegistryRoleDto( + LocalDate.of(2009, 11, 30), + null, "Proprietor" + ) + ) + ) + ) + ); + + public static final String BCREG_FACET_GP = """ + { + "searchResults": { + "results": [ + { + "bn": "", + "identifier": "FM0123432", + "legalType": "GP", + "name": "GENERAL PARTNERSHIP", + "parties": [ + { + "partyName": "JOHNATHAN VALELONG WICK", + "partyRoles": [ + "partner" + ], + "partyType": "person", + "score": 0.0 + }, + { + "partyName": "RUSKA ROMA", + "partyRoles": [ + "partner" + ], + "partyType": "person", + "score": 0.0 + } + ], + "score": 58.579773, + "status": "ACTIVE" + } + ], + "totalResults": 1 + } + }"""; + + public static final String BCREG_DOC_GP = """ + { + "business": { + "alternateNames": [ + { + "entityType": "GP", + "identifier": "FM0123432", + "name": "GENERAL PARTNERSHIP", + "registeredDate": "1994-04-25T07:00:00+00:00", + "startDate": null + } + ], + "goodStanding": true, + "hasCorrections": false, + "hasCourtOrders": false, + "hasRestrictions": false, + "identifier": "FM0123432", + "legalName": "JOHNATHAN VALELONG WICK, MARCEL ST. AMANT", + "legalType": "GP", + "state": "ACTIVE" + }, + "offices": { + "message": "FM0123432 address not found" + }, + "parties": [ + { + "officer": { + "email": "", + "firstName": "JOHNATHAN", + "lastName": "WICK", + "middleInitial": "VALELONG", + "partyType": "person" + }, + "roles": [ + { + "appointmentDate": "1994-04-25", + "cessationDate": null, + "roleType": "Partner" + } + ] + }, + { + "officer": { + "email": "", + "firstName": "RUSKA", + "lastName": "ROMA", + "partyType": "person" + }, + "roles": [ + { + "appointmentDate": "1994-04-25", + "cessationDate": null, + "roleType": "Partner" + } + ] + } + ] + }"""; + + public static final BcRegistryDocumentDto BCREG_DOCOBJ_GP = new BcRegistryDocumentDto( + new BcRegistryBusinessDto( + List.of( + new BcRegistryAlternateNameDto( + "GP", + "FM0123432", + "GENERAL PARTNERSHIP", + ZonedDateTime.of(1994, 4, 25, 7, 0, 0, 0, ZoneOffset.UTC), + null + ) + ), + true, + false, + false, + false, + "FM0123432", + "JOHNATHAN VALELONG WICK, MARCEL ST. AMANT", + "GP", + "ACTIVE" + ), + new BcRegistryOfficesDto(null), + List.of( + new BcRegistryPartyDto( + null, null, + new BcRegistryOfficerDto( + StringUtils.EMPTY, + "JOHNATHAN", + "WICK", + "VALELONG", + "person" + ), + List.of( + new BcRegistryRoleDto( + LocalDate.of(1994, 4, 25), + null, "Partner" + ) + ) + ), + new BcRegistryPartyDto( + null, null, + new BcRegistryOfficerDto( + StringUtils.EMPTY, + "RUSKA", + "ROMA", + null, + "person" + ), + List.of( + new BcRegistryRoleDto( + LocalDate.of(1994, 4, 25), + null, "Partner" + ) + ) + ) + ) + ); + + public static final String BCREG_FACET_XP = """ + { + "searchResults": { + "results": [ + { + "identifier": "XP0123456", + "legalType": "XP", + "name": "EXAMPLE FUND", + "parties": [ + { + "partyName": "EXAMPLE INVESTMENTS INC.", + "partyRoles": [ + "partner" + ], + "partyType": "organization", + "score": 0.0 + } + ], + "score": 50.60915, + "status": "ACTIVE" + } + ], + "totalResults": 1 + } + }"""; + + public static final BcRegistryDocumentDto BCREG_DOCOBJ_XP = new BcRegistryDocumentDto( + new BcRegistryBusinessDto( + List.of( + new BcRegistryAlternateNameDto( + "XP", + "XP0123456", + "EXAMPLE FUND", + null, + null + ) + ), + null, + false, + false, + false, + "XP0123456", + "EXAMPLE FUND", + "XP", + "ACTIVE" + ), + new BcRegistryOfficesDto( + new BcRegistryBusinessAdressesDto( + new BcRegistryAddressDto(null, null, null, null, null, null, null, null), + new BcRegistryAddressDto(null, null, null, null, null, null, null, null) + ) + ), + List.of() + ); + + +} diff --git a/backend/src/test/java/ca/bc/gov/app/TestConstants.java b/backend/src/test/java/ca/bc/gov/app/TestConstants.java index 53766091b1..0c5b196ca0 100644 --- a/backend/src/test/java/ca/bc/gov/app/TestConstants.java +++ b/backend/src/test/java/ca/bc/gov/app/TestConstants.java @@ -384,6 +384,94 @@ public class TestConstants { "title": "Registrar of Companies" } }"""; + + public static final String BCREG_DOC_DATA_SPORG = """ + { + "business": { + "alternateNames": [ + { + "entityType": "SP", + "identifier": "FM00004455", + "name": "JAMES BAXTER WOOD HANDCRAFTED FURNITURE", + "registeredDate": "2009-11-30T08:00:00+00:00", + "startDate": "2009-10-01" + } + ], + "goodStanding": true, + "identifier": "FM00004455", + "legalName": "SAMPLE HOLDINGS LTD.", + "legalType": "SP", + "state": "ACTIVE" + }, + "offices": { + "businessOffice": { + "deliveryAddress": { + "addressCity": "VICTORIA", + "addressCountry": "Canada", + "addressCountryDescription": "Canada", + "addressRegion": "BC", + "deliveryInstructions": "", + "postalCode": "V8V1X4", + "streetAddress": "501 Belleville Street", + "streetAddressAdditional": "" + }, + "mailingAddress": { + "addressCity": "VICTORIA", + "addressCountry": "Canada", + "addressCountryDescription": "Canada", + "addressRegion": "BC", + "deliveryInstructions": "", + "postalCode": "V8V1X4", + "streetAddress": "501 Belleville Street", + "streetAddressAdditional": "" + } + } + }, + "parties": [ + { + "deliveryAddress": { + "addressCity": "VICTORIA", + "addressCountry": "Canada", + "addressCountryDescription": "Canada", + "addressRegion": "BC", + "deliveryInstructions": "", + "postalCode": "V8V1X4", + "streetAddress": "501 Belleville Street", + "streetAddressAdditional": "" + }, + "mailingAddress": { + "addressCity": "VICTORIA", + "addressCountry": "Canada", + "addressCountryDescription": "Canada", + "addressRegion": "BC", + "deliveryInstructions": "", + "postalCode": "V8V1X4", + "streetAddress": "501 Belleville Street", + "streetAddressAdditional": "" + }, + "officer": { + "email": "", + "identifier": "BC0000001", + "organizationName": "SAMPLE HOLDINGS LTD.", + "partyType": "organization" + }, + "roles": [ + { + "appointmentDate": "1985-07-23", + "cessationDate": null, + "roleType": "Proprietor" + } + ] + } + ], + "registrarInfo": { + "endDate": null, + "name": "Wattles", + "startDate": "2022-06-01T00:00:00", + "title": "Registrar of Companies" + } + }"""; + public static final String SUBMISSION_LIST_CONTENT = """ [ { @@ -1031,5 +1119,76 @@ public static Map getClaims(String idpName) { } }"""; + public static final String STAFF_SUBMITTED_SPORG_JSON = """ + { + "businessInformation": { + "district": "", + "businessType": "R", + "legalType": "SP", + "clientType": "RSP", + "registrationNumber": "FM00004455", + "businessName": "JAMES BAXTER WOOD HANDCRAFTED FURNITURE", + "goodStandingInd": "Y", + "birthdate": "1974-08-12", + "firstName": "John", + "lastName": "Wick", + "identificationType": { + "value": "CDDL", + "text": "Canadian driver's licence", + "countryCode": "CA" + }, + "identificationCountry": "CA", + "clientIdentification": "54621654", + "identificationProvince": "BC" + }, + "location": { + "addresses": [ + { + "locationName": "Hangar", + "complementaryAddressOne": "", + "complementaryAddressTwo": null, + "streetAddress": "1234 Nowhere St", + "country": { + "value": "CA", + "text": "Canada" + }, + "province": { + "value": "BC", + "text": "British Columbia" + }, + "city": "Victoria", + "postalCode": "V8V8V8", + "businessPhoneNumber": "", + "secondaryPhoneNumber": "", + "faxNumber": "", + "emailAddress": "", + "notes": "", + "index": 0 + } + ], + "contacts": [ + { + "locationNames": [ + { + "value": "0", + "text": "Hangar" + } + ], + "contactType": { + "value": "BL", + "text": "Billing" + }, + "firstName": "John", + "lastName": "Wick", + "phoneNumber": "(250) 445-4540", + "secondaryPhoneNumber": "", + "faxNumber": "", + "email": "thatmail@maila.ca", + "index": 0 + } + ] + } + }"""; + } 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 4d1aa2d4ca..af61281c07 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 @@ -9,11 +9,13 @@ import static com.github.tomakehurst.wiremock.client.WireMock.status; import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; +import static org.junit.jupiter.api.Named.named; import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.csrf; import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockJwt; import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockUser; import ca.bc.gov.app.ApplicationConstant; +import ca.bc.gov.app.BcRegistryTestConstants; import ca.bc.gov.app.TestConstants; import ca.bc.gov.app.extensions.AbstractTestContainerIntegrationTest; import ca.bc.gov.app.extensions.WiremockLogNotifier; @@ -82,6 +84,7 @@ class ClientControllerIntegrationTest extends AbstractTestContainerIntegrationTe @BeforeEach public void reset() { bcRegistryStub.resetAll(); + chesStub.resetAll(); chesStub .stubFor( @@ -115,7 +118,7 @@ public void reset() { .build(); } - @ParameterizedTest + @ParameterizedTest(name = "{0}") @MethodSource("clientDetailing") @DisplayName("Client details") void shouldGetClientDetails( @@ -135,6 +138,27 @@ void shouldGetClientDetails( reset(); + bcRegistryStub + .stubFor( + post(urlPathEqualTo("/registry-search/api/v2/search/businesses")) + .withRequestBody(equalToJson( + String.format(""" + { + "query": { "value": "%s","name": "%s" }, + "categories":{ "status":["ACTIVE"] }, + "rows": 100, + "start":0 + }""", clientNumber, clientNumber) + ) + ) + .willReturn(okJson( + BcRegistryTestConstants.BCREG_FACET_ANY + .replace("C0123456", clientNumber) + .replace("EXAMPLE COMPANY LTD.", "SAMPLE COMPANY") + ) + ) + ); + bcRegistryStub .stubFor(post(urlPathEqualTo( "/registry-search/api/v1/businesses/" + clientNumber + "/documents/requests")) @@ -193,7 +217,7 @@ void shouldGetClientDetails( } - @ParameterizedTest + @ParameterizedTest(name = "{0}") @MethodSource("clientDetailingStaff") @DisplayName("Client details for staff") void shouldGetClientDetailsForStaff( @@ -213,6 +237,27 @@ void shouldGetClientDetailsForStaff( reset(); + bcRegistryStub + .stubFor( + post(urlPathEqualTo("/registry-search/api/v2/search/businesses")) + .withRequestBody(equalToJson( + String.format(""" + { + "query": { "value": "%s","name": "%s" }, + "categories":{ "status":["ACTIVE"] }, + "rows": 100, + "start":0 + }""", clientNumber, clientNumber) + ) + ) + .willReturn(okJson( + BcRegistryTestConstants.BCREG_FACET_ANY + .replace("C0123456", clientNumber) + .replace("EXAMPLE COMPANY LTD.", "SAMPLE COMPANY") + ) + ) + ); + bcRegistryStub .stubFor(post(urlPathEqualTo( "/registry-search/api/v1/businesses/" + clientNumber + "/documents/requests")) @@ -252,8 +297,10 @@ void shouldGetClientDetailsForStaff( .mutateWith(mockUser().roles(ApplicationConstant.ROLE_EDITOR)) .mutateWith( mockJwt() - .jwt(jwt -> jwt.claims(claims -> claims.putAll(TestConstants.getClaims("idir")))) - .authorities(new SimpleGrantedAuthority("ROLE_" + ApplicationConstant.ROLE_EDITOR)) + .jwt( + jwt -> jwt.claims(claims -> claims.putAll(TestConstants.getClaims("idir")))) + .authorities( + new SimpleGrantedAuthority("ROLE_" + ApplicationConstant.ROLE_EDITOR)) ) .get() .uri("/api/clients/{clientNumber}", Map.of("clientNumber", clientNumber)) @@ -276,11 +323,16 @@ void shouldGetDataFromIncorporation() { bcRegistryStub .stubFor( - get(urlPathEqualTo("/registry-search/api/v1/businesses/search/facets")) - .withQueryParam("category", equalTo("status:Active")) - .withQueryParam("start", equalTo("0")) - .withQueryParam("rows", equalTo("100")) - .withQueryParam("query", equalTo("value:BC0772006")) + post(urlPathEqualTo("/registry-search/api/v2/search/businesses")) + .withRequestBody(equalToJson(""" + { + "query": { "value": "BC0772006","name": "BC0772006" }, + "categories":{ "status":["ACTIVE"] }, + "rows": 100, + "start":0 + }""" + ) + ) .willReturn(okJson(TestConstants.ORGBOOK_INCORP_OK)) ); @@ -308,11 +360,16 @@ void shouldGetNoDataFromIncorporation() { bcRegistryStub .stubFor( - get(urlPathEqualTo("/registry-search/api/v1/businesses/search/facets")) - .withQueryParam("category", equalTo("status:Active")) - .withQueryParam("start", equalTo("0")) - .withQueryParam("rows", equalTo("100")) - .withQueryParam("query", equalTo("value:BC0000000")) + post(urlPathEqualTo("/registry-search/api/v2/search/businesses")) + .withRequestBody(equalToJson(""" + { + "query": { "value": "BC0000000","name": "BC0000000" }, + "categories":{ "status":["ACTIVE"] }, + "rows": 100, + "start":0 + }""" + ) + ) .willReturn(okJson(TestConstants.ORGBOOK_INCORP_EMPTY)) ); @@ -340,11 +397,16 @@ void shouldGetDataFromNameLookup() { bcRegistryStub .stubFor( - get(urlPathEqualTo("/registry-search/api/v1/businesses/search/facets")) - .withQueryParam("category", equalTo("status:Active")) - .withQueryParam("start", equalTo("0")) - .withQueryParam("rows", equalTo("100")) - .withQueryParam("query", equalTo("value:Power")) + post(urlPathEqualTo("/registry-search/api/v2/search/businesses")) + .withRequestBody(equalToJson(""" + { + "query": { "value": "Power","name": "Power" }, + "categories":{ "status":["ACTIVE"] }, + "rows": 100, + "start":0 + }""" + ) + ) .willReturn(okJson(TestConstants.ORGBOOK_INCORP_OK)) ); @@ -371,11 +433,16 @@ void shouldGetNoDataFromNameLookup() { bcRegistryStub .stubFor( - get(urlPathEqualTo("/registry-search/api/v1/businesses/search/facets")) - .withQueryParam("category", equalTo("status:Active")) - .withQueryParam("start", equalTo("0")) - .withQueryParam("rows", equalTo("100")) - .withQueryParam("query", equalTo("value:Jhon")) + post(urlPathEqualTo("/registry-search/api/v2/search/businesses")) + .withRequestBody(equalToJson(""" + { + "query": { "value": "Jhon","name": "Jhon" }, + "categories":{ "status":["ACTIVE"] }, + "rows": 100, + "start":0 + }""" + ) + ) .willReturn(okJson(TestConstants.ORGBOOK_INCORP_EMPTY)) ); @@ -458,65 +525,64 @@ private static Stream clientDetailing() { return Stream.of( Arguments.of( - "AA0000001", + named("All worked fine","AA0000001"), 200, TestConstants.BCREG_DOC_REQ_RES, 200, TestConstants.BCREG_DOC_DATA, 200, TestConstants.BCREG_RESPONSE_OK, TestConstants.LEGACY_EMPTY ), Arguments.of( - "AA0000001", + named("Duplicated with all good due to legacy","AA0000001"), 200, TestConstants.BCREG_DOC_REQ_RES, 200, TestConstants.BCREG_DOC_DATA, 409, TestConstants.BCREG_RESPONSE_DUP, TestConstants.LEGACY_OK ), Arguments.of( - "AA0000001", + named("All good, even with some legacy data","AA0000001"), 200, TestConstants.BCREG_DOC_REQ_RES, 200, TestConstants.BCREG_DOC_DATA, 200, TestConstants.BCREG_RESPONSE_OK, TestConstants.LEGACY_OK.replace("0000001", "0000002") ), Arguments.of( - "AA0000001", + named("Can't find it, but facet can","AA0000001"), 404, TestConstants.BCREG_NOK, 404, TestConstants.BCREG_NOK, - 404, TestConstants.BCREG_RESPONSE_NOK, + 200, BcRegistryTestConstants.BCREG_RESPONSE_ANY, TestConstants.LEGACY_EMPTY ), Arguments.of( - "AA0000001", + named("Can't find what you're looking, but facet saved you","AA0000001"), 200, TestConstants.BCREG_DOC_REQ_RES, 404, TestConstants.BCREG_NOK, - 404, TestConstants.BCREG_RESPONSE_NOK, + 200, BcRegistryTestConstants.BCREG_RESPONSE_ANY, TestConstants.LEGACY_EMPTY ), Arguments.of( - "AA0000001", + named("Bc registry key is wrong","AA0000001"), 200, TestConstants.BCREG_DOC_REQ_RES, 401, TestConstants.BCREG_401, 401, TestConstants.BCREG_RESPONSE_401, TestConstants.LEGACY_EMPTY ), Arguments.of( - "AA0000001", + named("All keys went south","AA0000001"), 401, TestConstants.BCREG_401, 401, TestConstants.BCREG_401, 401, TestConstants.BCREG_RESPONSE_401, TestConstants.LEGACY_EMPTY ), Arguments.of( - "AA0000001", + named("Errors and keys","AA0000001"), 400, TestConstants.BCREG_400, 400, TestConstants.BCREG_400, 401, TestConstants.BCREG_RESPONSE_401, TestConstants.LEGACY_EMPTY ), - Arguments.of( - "AA0000001", + named("Sole prop from org is a no bueno","AA0000001"), 200, TestConstants.BCREG_DOC_REQ_RES, 200, TestConstants.BCREG_DOC_DATA .replace("\"partyType\": \"person\"", "\"partyType\": \"organization\"") @@ -532,91 +598,91 @@ private static Stream clientDetailing() { private static Stream clientDetailingStaff() { return - Stream.of( - Arguments.of( - "AA0000001", - 200, TestConstants.BCREG_DOC_REQ_RES, - 200, TestConstants.BCREG_DOC_DATA, - TestConstants.LEGACY_EMPTY, - 200, TestConstants.BCREG_RESPONSE_OK - ), - Arguments.of( - "AA0000001", - 200, TestConstants.BCREG_DOC_REQ_RES, - 200, TestConstants.BCREG_DOC_DATA, - TestConstants.LEGACY_OK, - 409, TestConstants.BCREG_RESPONSE_DUP - ), - Arguments.of( - "AA0000001", - 200, TestConstants.BCREG_DOC_REQ_RES, - 200, TestConstants.BCREG_DOC_DATA, - TestConstants.LEGACY_OK.replace("0000001", "0000002"), - 200, TestConstants.BCREG_RESPONSE_OK - ), - Arguments.of( - "AA0000001", - 404, TestConstants.BCREG_NOK, - 404, TestConstants.BCREG_NOK, - TestConstants.LEGACY_EMPTY, - 404, TestConstants.BCREG_RESPONSE_NOK - ), - Arguments.of( - "AA0000001", - 200, TestConstants.BCREG_DOC_REQ_RES, - 404, TestConstants.BCREG_NOK, - TestConstants.LEGACY_EMPTY, - 404, TestConstants.BCREG_RESPONSE_NOK - ), - Arguments.of( - "AA0000001", - 200, TestConstants.BCREG_DOC_REQ_RES, - 401, TestConstants.BCREG_401, - TestConstants.LEGACY_EMPTY, - 401, TestConstants.BCREG_RESPONSE_401 - ), - Arguments.of( - "AA0000001", - 401, TestConstants.BCREG_401, - 401, TestConstants.BCREG_401, - TestConstants.LEGACY_EMPTY, - 401, TestConstants.BCREG_RESPONSE_401 - ), - Arguments.of( - "AA0000001", - 400, TestConstants.BCREG_400, - 400, TestConstants.BCREG_400, - TestConstants.LEGACY_EMPTY, - 401, TestConstants.BCREG_RESPONSE_401 - ), - Arguments.of( - "AA0000001", - 200, TestConstants.BCREG_DOC_REQ_RES, - 400, TestConstants.BCREG_400, - TestConstants.LEGACY_EMPTY, - 401, TestConstants.BCREG_RESPONSE_401 - ), - Arguments.of( - "AA0000001", - 200, TestConstants.BCREG_DOC_REQ_RES, - 200, TestConstants.BCREG_DOC_DATA - .replace("\"partyType\": \"person\"", "\"partyType\": \"organization\"") - .replace("\"firstName\": \"JAMES\",", "\"organizationName\": \"OWNER ORG\",") - .replace("\"lastName\": \"BAXTER\",", "\"identifier\": \"BB0000001\",") - .replace("\"middleInitial\": \"middleInitial\",", "\"id\": \"1234467\",") - , - TestConstants.LEGACY_EMPTY, - 200, TestConstants.BCREG_RESPONSE_NOCONTACTOK - ), - Arguments.of( - "AA0000001", - 200, TestConstants.BCREG_DOC_REQ_RES, - 200, TestConstants.BCREG_DOC_DATA - .replace("\"legalType\": \"SP\"", "\"legalType\": \"LP\""), - TestConstants.LEGACY_EMPTY, - 200, TestConstants.BCREG_RESPONSE_OK - ) - ); + Stream.of( + Arguments.of( + named("Bc registry ok and not on legacy", "AA0000001"), + 201, TestConstants.BCREG_DOC_REQ_RES, + 200, TestConstants.BCREG_DOC_DATA, + TestConstants.LEGACY_EMPTY, + 200, TestConstants.BCREG_RESPONSE_OK + ), + Arguments.of( + named("Bc registry ok and found on legacy", "AA0000001"), + 201, TestConstants.BCREG_DOC_REQ_RES, + 200, TestConstants.BCREG_DOC_DATA, + TestConstants.LEGACY_OK, + 409, TestConstants.BCREG_RESPONSE_DUP + ), + Arguments.of( + named("Bc registry ok and legacy with other ids", "AA0000001"), + 201, TestConstants.BCREG_DOC_REQ_RES, + 200, TestConstants.BCREG_DOC_DATA, + TestConstants.LEGACY_OK.replace("0000001", "0000002"), + 200, TestConstants.BCREG_RESPONSE_OK + ), + Arguments.of( + named("not found on bc registry", "AA0000001"), + 404, TestConstants.BCREG_NOK, + 404, TestConstants.BCREG_NOK, + TestConstants.LEGACY_EMPTY, + 200, BcRegistryTestConstants.BCREG_RESPONSE_ANY + ), + Arguments.of( + named("Bc Registry ok with no doc and no legacy", "AA0000001"), + 201, TestConstants.BCREG_DOC_REQ_RES, + 404, TestConstants.BCREG_NOK, + TestConstants.LEGACY_EMPTY, + 200, BcRegistryTestConstants.BCREG_RESPONSE_ANY + ), + Arguments.of( + named("Key error on bc registry", "AA0000001"), + 201, TestConstants.BCREG_DOC_REQ_RES, + 401, TestConstants.BCREG_401, + TestConstants.LEGACY_EMPTY, + 401, TestConstants.BCREG_RESPONSE_401 + ), + Arguments.of( + named("Full key error", "AA0000001"), + 401, TestConstants.BCREG_401, + 401, TestConstants.BCREG_401, + TestConstants.LEGACY_EMPTY, + 401, TestConstants.BCREG_RESPONSE_401 + ), + Arguments.of( + named("400 on Bc Registry", "AA0000001"), + 400, TestConstants.BCREG_400, + 400, TestConstants.BCREG_400, + TestConstants.LEGACY_EMPTY, + 401, TestConstants.BCREG_RESPONSE_401 + ), + Arguments.of( + named("Bc Registry with no doc but ok on request", "AA0000001"), + 201, TestConstants.BCREG_DOC_REQ_RES, + 400, TestConstants.BCREG_400, + TestConstants.LEGACY_EMPTY, + 401, TestConstants.BCREG_RESPONSE_401 + ), + Arguments.of( + named("Bc Registry with owner org", "AA0000001"), + 201, TestConstants.BCREG_DOC_REQ_RES, + 200, TestConstants.BCREG_DOC_DATA + .replace("\"partyType\": \"person\"", "\"partyType\": \"organization\"") + .replace("\"firstName\": \"JAMES\",", "\"organizationName\": \"OWNER ORG\",") + .replace("\"lastName\": \"BAXTER\",", "\"identifier\": \"BB0000001\",") + .replace("\"middleInitial\": \"middleInitial\",", "\"id\": \"1234467\",") + , + TestConstants.LEGACY_EMPTY, + 200, TestConstants.BCREG_RESPONSE_NOCONTACTOK + ), + Arguments.of( + named("BC Registry legal type change", "AA0000001"), + 201, TestConstants.BCREG_DOC_REQ_RES, + 200, TestConstants.BCREG_DOC_DATA + .replace("\"legalType\": \"SP\"", "\"legalType\": \"LP\""), + TestConstants.LEGACY_EMPTY, + 200, TestConstants.BCREG_RESPONSE_OK + ) + ); } } diff --git a/backend/src/test/java/ca/bc/gov/app/controller/client/ClientStaffSubmissionControllerIntegrationTest.java b/backend/src/test/java/ca/bc/gov/app/controller/client/ClientStaffSubmissionControllerIntegrationTest.java index 27c7f719ff..d025c8904e 100644 --- a/backend/src/test/java/ca/bc/gov/app/controller/client/ClientStaffSubmissionControllerIntegrationTest.java +++ b/backend/src/test/java/ca/bc/gov/app/controller/client/ClientStaffSubmissionControllerIntegrationTest.java @@ -4,6 +4,7 @@ import static com.github.tomakehurst.wiremock.client.WireMock.get; import static com.github.tomakehurst.wiremock.client.WireMock.ok; import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.status; import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.csrf; @@ -58,7 +59,7 @@ class ClientStaffSubmissionControllerIntegrationTest .options( wireMockConfig() .port(10010) - .notifier(new WiremockLogNotifier()) + //.notifier(new WiremockLogNotifier()) .asynchronousResponseEnabled(true) .stubRequestLoggingDisabled(false) ) @@ -78,6 +79,19 @@ class ClientStaffSubmissionControllerIntegrationTest .configureStaticDsl(true) .build(); + @RegisterExtension + static WireMockExtension bcRegistryStub = WireMockExtension + .newInstance() + .options( + wireMockConfig() + .port(10040) + .notifier(new WiremockLogNotifier()) + .asynchronousResponseEnabled(true) + .stubRequestLoggingDisabled(false) + ) + .configureStaticDsl(true) + .build(); + @Autowired protected WebTestClient client; @Autowired @@ -199,6 +213,52 @@ void shouldSubmitIndividualClientSubmission() throws JsonProcessingException { } + @Test + @DisplayName("Sole proprietorship not owner by person is not allowed") + @Order(3) + void shouldNotAllowSubmissionFromNonPersonProprietor() throws JsonProcessingException { + + bcRegistryStub + .stubFor( + post("/registry-search/api/v1/businesses/FM00004455/documents/requests") + .willReturn( + status(201) + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(TestConstants.BCREG_DOC_REQ_RES) + ) + ); + + bcRegistryStub + .stubFor( + get("/registry-search/api/v1/businesses/FM00004455/documents/aa0a00a0a") + .willReturn( + status(200) + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(TestConstants.BCREG_DOC_DATA_SPORG) + ) + ); + + ClientSubmissionDto dto = mapper.readValue( + TestConstants.STAFF_SUBMITTED_SPORG_JSON, + ClientSubmissionDto.class + ); + + client + .mutateWith(csrf()) + .mutateWith(mockUser().roles(ApplicationConstant.ROLE_EDITOR)) + .mutateWith( + mockJwt() + .jwt(jwt -> jwt.claims(claims -> claims.putAll(TestConstants.getClaims("idir")))) + .authorities(new SimpleGrantedAuthority("ROLE_" + ApplicationConstant.ROLE_EDITOR)) + ) + .post() + .uri("/api/clients/submissions/staff") + .body(Mono.just(dto), ClientSubmissionDto.class) + .exchange() + .expectStatus().isBadRequest(); + + } + /** * Marks a submission with a specific client number if it's not already marked. This method * performs several operations in a reactive pipeline: diff --git a/backend/src/test/java/ca/bc/gov/app/extensions/ClientMatchDataGenerator.java b/backend/src/test/java/ca/bc/gov/app/extensions/ClientMatchDataGenerator.java index 5c7de21094..121d6f8cd7 100644 --- a/backend/src/test/java/ca/bc/gov/app/extensions/ClientMatchDataGenerator.java +++ b/backend/src/test/java/ca/bc/gov/app/extensions/ClientMatchDataGenerator.java @@ -121,7 +121,7 @@ public static ClientSubmissionDto getRegisteredSP( .businessInformation() .withRegistrationNumber(registrationNumber) .withBusinessName(businessName) - .withBusinessType("R") + .withBusinessType("") .withLegalType("SP") .withWorkSafeBcNumber(workSafeBcNumber) .withDoingBusinessAs(doingBusinessAs) diff --git a/backend/src/test/java/ca/bc/gov/app/service/bcregistry/BcRegistryServiceIntegrationTest.java b/backend/src/test/java/ca/bc/gov/app/service/bcregistry/BcRegistryServiceIntegrationTest.java new file mode 100644 index 0000000000..3168632f1b --- /dev/null +++ b/backend/src/test/java/ca/bc/gov/app/service/bcregistry/BcRegistryServiceIntegrationTest.java @@ -0,0 +1,362 @@ +package ca.bc.gov.app.service.bcregistry; + +import static ca.bc.gov.app.BcRegistryTestConstants.BCREG_DOCOBJ_ANY; +import static ca.bc.gov.app.BcRegistryTestConstants.BCREG_DOCOBJ_GP; +import static ca.bc.gov.app.BcRegistryTestConstants.BCREG_DOCOBJ_SP_ORG; +import static ca.bc.gov.app.BcRegistryTestConstants.BCREG_DOCOBJ_SP_PERSON; +import static ca.bc.gov.app.BcRegistryTestConstants.BCREG_DOCOBJ_XP; +import static ca.bc.gov.app.BcRegistryTestConstants.BCREG_DOC_GP; +import static ca.bc.gov.app.BcRegistryTestConstants.BCREG_DOC_REQ_FAIL; +import static ca.bc.gov.app.BcRegistryTestConstants.BCREG_DOC_REQ_RES; +import static ca.bc.gov.app.BcRegistryTestConstants.BCREG_DOC_SP_ORG; +import static ca.bc.gov.app.BcRegistryTestConstants.BCREG_DOC_SP_PERSON; +import static ca.bc.gov.app.BcRegistryTestConstants.BCREG_FACET_401; +import static ca.bc.gov.app.BcRegistryTestConstants.BCREG_FACET_500; +import static ca.bc.gov.app.BcRegistryTestConstants.BCREG_FACET_ANY; +import static ca.bc.gov.app.BcRegistryTestConstants.BCREG_FACET_EMPTY; +import static ca.bc.gov.app.BcRegistryTestConstants.BCREG_FACET_FAIL; +import static ca.bc.gov.app.BcRegistryTestConstants.BCREG_FACET_GP; +import static ca.bc.gov.app.BcRegistryTestConstants.BCREG_FACET_SP_ORG; +import static ca.bc.gov.app.BcRegistryTestConstants.BCREG_FACET_SP_PERSON; +import static ca.bc.gov.app.BcRegistryTestConstants.BCREG_FACET_XP; +import static ca.bc.gov.app.BcRegistryTestConstants.NO_DATA; +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.status; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; +import static org.junit.jupiter.api.Named.named; + +import ca.bc.gov.app.dto.bcregistry.BcRegistryDocumentDto; +import ca.bc.gov.app.dto.bcregistry.BcRegistryFacetPartyDto; +import ca.bc.gov.app.dto.bcregistry.BcRegistryFacetSearchResultEntryDto; +import ca.bc.gov.app.extensions.AbstractTestContainerIntegrationTest; +import ca.bc.gov.app.extensions.WiremockLogNotifier; +import com.github.tomakehurst.wiremock.junit5.WireMockExtension; +import java.util.List; +import java.util.stream.Stream; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.server.ResponseStatusException; +import reactor.test.StepVerifier; +import reactor.test.StepVerifier.FirstStep; + +@Slf4j +@DisplayName("Integrated Test | BC Registry Service") +class BcRegistryServiceIntegrationTest extends AbstractTestContainerIntegrationTest { + + @Autowired + private BcRegistryService service; + + @RegisterExtension + static WireMockExtension bcRegistryStub = WireMockExtension + .newInstance() + .options( + wireMockConfig() + .port(10040) + .notifier(new WiremockLogNotifier()) + .asynchronousResponseEnabled(true) + .stubRequestLoggingDisabled(false) + ) + .configureStaticDsl(true) + .build(); + + + @BeforeEach + public void setUp() { + bcRegistryStub.resetAll(); + } + + @ParameterizedTest(name = "Search by facets: {0}") + @MethodSource("byFacets") + @DisplayName("should search and get facets") + void shouldSearch( + String data, + String response, + int responseStatus, + BcRegistryFacetSearchResultEntryDto expected + ) { + + bcRegistryStub + .stubFor( + post(urlPathEqualTo("/registry-search/api/v2/search/businesses")) + .withRequestBody(equalToJson( + String.format(""" + { + "query": { "value": "%s","name": "%s" }, + "categories":{ "status":["ACTIVE"] }, + "rows": 100, + "start":0 + }""", data, data) + ) + ) + .willReturn( + aResponse() + .withStatus(responseStatus) + .withHeader("Content-Type", "application/json") + .withBody(response) + ) + ); + + FirstStep step = + service + .searchByFacets(data) + .as(StepVerifier::create); + + if (responseStatus != 200) { + step.expectError(ResponseStatusException.class).verify(); + } else { + if (expected == null) { + step.expectNextCount(0).verifyComplete(); + } else { + step.expectNext(expected).verifyComplete(); + } + } + } + + @ParameterizedTest(name = "Get document: {0}") + @MethodSource("byDocument") + @DisplayName("should request document") + void shouldRequestData( + String data, + String documentRequestResponse, + int documentRequestStatus, + String documentResponseResponse, + int documentResponseStatus, + String facetResponse, + boolean shouldFail, + BcRegistryDocumentDto expected + ) { + + bcRegistryStub + .stubFor( + post(urlPathEqualTo("/registry-search/api/v2/search/businesses")) + .willReturn( + aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBody(facetResponse) + ) + ); + + bcRegistryStub + .stubFor(post(urlPathEqualTo( + "/registry-search/api/v1/businesses/" + data + "/documents/requests")) + .willReturn( + status(documentRequestStatus) + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(documentRequestResponse) + ) + ); + + bcRegistryStub + .stubFor(get(urlPathEqualTo( + "/registry-search/api/v1/businesses/" + data + "/documents/aa0a00a0a")) + .willReturn( + status(documentResponseStatus) + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(documentResponseResponse) + ) + ); + + FirstStep step = + service + .requestDocumentData(data) + .as(StepVerifier::create); + + if (shouldFail) { + step.expectError(ResponseStatusException.class).verify(); + } else { + step.expectNext(expected).verifyComplete(); + } + } + + private static Stream byFacets() { + return Stream.of( + Arguments.of( + named("Request messed up", "C0123456"), + BCREG_FACET_FAIL, 400, null + ), + Arguments.of( + named("Wrong key", "C0123456"), + BCREG_FACET_401, 401, null + ), + Arguments.of( + named("500 error", "C0123456"), + BCREG_FACET_500, 500, null + ), + Arguments.of( + named("No data", "C0123456"), + BCREG_FACET_EMPTY, 200, null + ), + Arguments.of( + named("Corporation", "C0123456"), + BCREG_FACET_ANY, 200, + new BcRegistryFacetSearchResultEntryDto( + "100000000000001", + "C0123456", + "C", + "EXAMPLE COMPANY LTD.", + "ACTIVE", + true, + null + ) + ), + Arguments.of( + named("Sole Prop owned by corporation", "FM0123456"), + BCREG_FACET_SP_ORG, 200, + new BcRegistryFacetSearchResultEntryDto( + "100000000000002", + "FM0123456", + "SP", + "EXAMPLE SOLE PROPRIETORSHIP", + "ACTIVE", + null, + List.of( + new BcRegistryFacetPartyDto( + "EXAMPLE COMPANY LTD.", + List.of("proprietor"), + "organization" + ) + ) + ) + ), + Arguments.of( + named("Sole Prop owned by person", "FM0123210"), + BCREG_FACET_SP_PERSON, 200, + new BcRegistryFacetSearchResultEntryDto( + "100000000000003", + "FM0123210", + "SP", + "EXAMPLE SOLE PROPRIETORSHIP", + "ACTIVE", + null, + List.of( + new BcRegistryFacetPartyDto( + "JOHNATHAN WICK", + List.of("proprietor"), + "person" + ) + ) + ) + ), + Arguments.of( + named("General partnership with multiple partners", "FM0123432"), + BCREG_FACET_GP, 200, + new BcRegistryFacetSearchResultEntryDto( + StringUtils.EMPTY, + "FM0123432", + "GP", + "GENERAL PARTNERSHIP", + "ACTIVE", + null, + List.of( + new BcRegistryFacetPartyDto( + "JOHNATHAN VALELONG WICK", + List.of("partner"), + "person" + ), + new BcRegistryFacetPartyDto( + "RUSKA ROMA", + List.of("partner"), + "person" + ) + ) + ) + ), + Arguments.of( + named("XP means some kind of partnership", "XP0123456"), + BCREG_FACET_XP, 200, + new BcRegistryFacetSearchResultEntryDto( + null, + "XP0123456", + "XP", + "EXAMPLE FUND", + "ACTIVE", + null, + List.of( + new BcRegistryFacetPartyDto( + "EXAMPLE INVESTMENTS INC.", + List.of("partner"), + "organization" + ) + ) + ) + ) + ); + } + + private static Stream byDocument() { + return + Stream.of( + Arguments.of( + named("Request messed up", "C0123456"), + BCREG_FACET_FAIL, 400, + BCREG_FACET_FAIL, 400, + NO_DATA, true, + null + ), + Arguments.of( + named("Wrong key", "C0123456"), + BCREG_FACET_401, 401, + BCREG_FACET_401, 401, + NO_DATA, true, + null + ), + Arguments.of( + named("500 error", "C0123456"), + BCREG_FACET_500, 500, + BCREG_FACET_500, 500, + NO_DATA, true, + null + ), + Arguments.of( + named("Company do not have response", "C0123456"), + BCREG_DOC_REQ_FAIL, 400, + NO_DATA, 200, + BCREG_FACET_ANY, false, + BCREG_DOCOBJ_ANY + ), + Arguments.of( + named("Sole proprietorship owned by person", "FM0123210"), + BCREG_DOC_REQ_RES, 201, + BCREG_DOC_SP_PERSON, 200, + BCREG_FACET_EMPTY, false, + BCREG_DOCOBJ_SP_PERSON + ), + Arguments.of( + named("Sole proprietorship owned by organization", "FM0123456"), + BCREG_DOC_REQ_RES, 201, + BCREG_DOC_SP_ORG, 200, + BCREG_FACET_EMPTY, false, + BCREG_DOCOBJ_SP_ORG + ), + Arguments.of( + named("General partnership with multiple owners", "FM0123432"), + BCREG_DOC_REQ_RES, 201, + BCREG_DOC_GP, 200, + BCREG_FACET_EMPTY, false, + BCREG_DOCOBJ_GP + ), + Arguments.of( + named("XP with a single org owner", "XP0123456"), + BCREG_DOC_REQ_FAIL, 400, + NO_DATA, 200, + BCREG_FACET_XP, false, + BCREG_DOCOBJ_XP + ) + ); + + } + +} \ No newline at end of file diff --git a/backend/src/test/java/ca/bc/gov/app/service/client/ClientMatchServiceIntegrationTest.java b/backend/src/test/java/ca/bc/gov/app/service/client/ClientMatchServiceIntegrationTest.java index 54cf4c25d6..e2c5c7686e 100644 --- a/backend/src/test/java/ca/bc/gov/app/service/client/ClientMatchServiceIntegrationTest.java +++ b/backend/src/test/java/ca/bc/gov/app/service/client/ClientMatchServiceIntegrationTest.java @@ -25,7 +25,6 @@ import java.time.format.DateTimeFormatter; import java.util.List; import java.util.stream.Stream; -import org.apache.commons.lang3.NotImplementedException; import org.apache.commons.lang3.StringUtils; import org.assertj.core.api.Condition; import org.junit.jupiter.api.DisplayName; diff --git a/backend/src/test/java/ca/bc/gov/app/service/client/matches/RegisteredStepMatcherTest.java b/backend/src/test/java/ca/bc/gov/app/service/client/matches/RegisteredStepMatcherTest.java index 0437b9c01e..2d98697e28 100644 --- a/backend/src/test/java/ca/bc/gov/app/service/client/matches/RegisteredStepMatcherTest.java +++ b/backend/src/test/java/ca/bc/gov/app/service/client/matches/RegisteredStepMatcherTest.java @@ -31,6 +31,7 @@ import reactor.core.publisher.Flux; import reactor.test.StepVerifier; +@SuppressWarnings("ALL") @DisplayName("Unit Test | Registered Step Matcher") @Slf4j class RegisteredStepMatcherTest { @@ -340,6 +341,28 @@ private static Stream matchStep() { named("dba full matched", Flux.just(ClientMatchDataGenerator.getForestClientDto("00000007"))), true, false + ), + Arguments.of( + ClientMatchDataGenerator + .getRegisteredSP( + "FM123456", + "Santa Marta Corp", + StringUtils.EMPTY, + "Santa Marta Corp", + StringUtils.EMPTY, + StringUtils.EMPTY, + StringUtils.EMPTY, + LocalDate.of(1970, 1, 12) + ), + named("no individual request done", Flux.empty()), + named("no fuzzy name", Flux.empty()), + named("no registration", Flux.empty()), + named("no full name", Flux.empty()), + named("no acronym", Flux.empty()), + named("no dba fuzzy", Flux.empty()), + named("no dba full", Flux.empty()), + false, + false ) ); } diff --git a/backend/src/test/java/ca/bc/gov/app/validator/business/BusinessInformationBusinessRegisteredNumberValidatorTest.java b/backend/src/test/java/ca/bc/gov/app/validator/business/BusinessInformationBusinessRegisteredNumberValidatorTest.java index ffd1c85acd..b0d06cd822 100644 --- a/backend/src/test/java/ca/bc/gov/app/validator/business/BusinessInformationBusinessRegisteredNumberValidatorTest.java +++ b/backend/src/test/java/ca/bc/gov/app/validator/business/BusinessInformationBusinessRegisteredNumberValidatorTest.java @@ -54,6 +54,7 @@ void shouldValidate( .thenReturn(Flux.just( new BcRegistryDocumentDto( new BcRegistryBusinessDto( + List.of(), isGoodStanding, false, false, diff --git a/frontend/cypress/e2e/FormBCSCPage.cy.ts b/frontend/cypress/e2e/pages/FormBCSCPage.cy.ts similarity index 99% rename from frontend/cypress/e2e/FormBCSCPage.cy.ts rename to frontend/cypress/e2e/pages/FormBCSCPage.cy.ts index 9292a1c8cf..64c1dbed5f 100644 --- a/frontend/cypress/e2e/FormBCSCPage.cy.ts +++ b/frontend/cypress/e2e/pages/FormBCSCPage.cy.ts @@ -1,5 +1,3 @@ -import { delay } from "cypress/types/bluebird"; - /* eslint-disable no-undef */ describe("BCSC Form", () => { diff --git a/frontend/cypress/e2e/FormGeneral.cy.ts b/frontend/cypress/e2e/pages/FormGeneral.cy.ts similarity index 100% rename from frontend/cypress/e2e/FormGeneral.cy.ts rename to frontend/cypress/e2e/pages/FormGeneral.cy.ts diff --git a/frontend/cypress/e2e/FormStaffPage.cy.ts b/frontend/cypress/e2e/pages/FormStaffPage.cy.ts similarity index 100% rename from frontend/cypress/e2e/FormStaffPage.cy.ts rename to frontend/cypress/e2e/pages/FormStaffPage.cy.ts diff --git a/frontend/cypress/e2e/FormStaffPageFuzzy.cy.ts b/frontend/cypress/e2e/pages/FormStaffPageFuzzy.cy.ts similarity index 100% rename from frontend/cypress/e2e/FormStaffPageFuzzy.cy.ts rename to frontend/cypress/e2e/pages/FormStaffPageFuzzy.cy.ts diff --git a/frontend/cypress/e2e/FormStaffPageSubmission.cy.ts b/frontend/cypress/e2e/pages/FormStaffPageSubmission.cy.ts similarity index 100% rename from frontend/cypress/e2e/FormStaffPageSubmission.cy.ts rename to frontend/cypress/e2e/pages/FormStaffPageSubmission.cy.ts diff --git a/frontend/cypress/e2e/SubmissionReviewPage.cy.ts b/frontend/cypress/e2e/pages/SubmissionReviewPage.cy.ts similarity index 99% rename from frontend/cypress/e2e/SubmissionReviewPage.cy.ts rename to frontend/cypress/e2e/pages/SubmissionReviewPage.cy.ts index 2391aeee03..1c4fac67eb 100644 --- a/frontend/cypress/e2e/SubmissionReviewPage.cy.ts +++ b/frontend/cypress/e2e/pages/SubmissionReviewPage.cy.ts @@ -1,4 +1,4 @@ -import testCases from "../fixtures/test-cases-review-submissions.json"; +import testCases from "../../fixtures/test-cases-review-submissions.json"; /* eslint-disable no-undef */ describe("Submission Review Page", () => { diff --git a/frontend/tests/components/pages/staffform/BcRegisteredClientInformationWizardStep.cy.ts b/frontend/cypress/e2e/pages/staffform/BcRegisteredClientInformationWizardStep.cy.ts similarity index 52% rename from frontend/tests/components/pages/staffform/BcRegisteredClientInformationWizardStep.cy.ts rename to frontend/cypress/e2e/pages/staffform/BcRegisteredClientInformationWizardStep.cy.ts index a2136941f5..fc1e837704 100644 --- a/frontend/tests/components/pages/staffform/BcRegisteredClientInformationWizardStep.cy.ts +++ b/frontend/cypress/e2e/pages/staffform/BcRegisteredClientInformationWizardStep.cy.ts @@ -1,409 +1,47 @@ -import BcRegisteredClientInformationWizardStep from "@/pages/staffform/BcRegisteredClientInformationWizardStep.vue"; -import { newFormDataDto, type FormDataDto } from "@/dto/ApplyClientNumberDto"; +import testCases from "../../../fixtures/staff/bcregisteredscenarios.json"; -import "@/helpers/validators/StaffFormValidations"; +/* eslint-disable no-undef */ +describe("Bc Registered Staff Wizard Step", () => { -describe("", () => { beforeEach(() => { - cy.viewport(1056, 800); + cy.viewport(1920, 1080); + + cy.intercept("GET", '/api/clients/submissions?page=0&size=10', { + fixture: "submissions.json", + headers: { + "x-total-count": "1", + "content-type": "application/json;charset=UTF-8", + "Access-Control-Expose-Headers": "x-total-count", + }, + }).as("getSubmissions"); + cy.intercept("GET", "/api/clients/name/exi", { fixture: "clients/bcreg_ac_list1.json", }); cy.intercept("GET", "/api/clients/C1234567", { fixture: "clients/bcreg_C1234567.json", }); - }); - - it("should render the component", () => { - const formContent: FormDataDto = newFormDataDto(); - formContent.businessInformation.businessName = ""; - formContent.businessInformation.businessType = "BCR"; - cy.log("formContent", formContent); - - cy.mount(BcRegisteredClientInformationWizardStep, { - props: { - data: formContent, - active: true, - autofocus: false, - }, - }); - - // Initially, only the client name and the info notification should exist - cy.get("#businessName").should("exist"); - cy.get("cds-inline-notification").should("exist"); - - //Just a check to make sure the fields are not visible - cy.get(".read-only-box").should("not.exist"); - - // Then, when a client is selected, the rest of the form should appear - cy.selectAutocompleteEntry("#businessName", "exi", "C1234567"); - - cy.get(".read-only-box") - .should("exist") - .find("cds-inline-notification") - .should("exist"); - - cy.get(".read-only-box > :nth-child(2) > .title-group-01 > .label-01") - .should("exist") - .and("have.text", "Type"); - - cy.get(".read-only-box > :nth-child(2) > .body-compact-01") - .should("exist") - .and("have.text", "Corporation"); - - cy.get(".read-only-box > :nth-child(4) > .title-group-01 > .label-01") - .should("exist") - .and("have.text", "Registration number"); - - cy.get(".read-only-box > :nth-child(4) > .body-compact-01") - .should("exist") - .and("have.text", "C1234567"); - - cy.get(".read-only-box > :nth-child(6) > .title-group-01 > .label-01") - .should("exist") - .and("have.text", "BC Registries standing"); - - cy.get( - ".read-only-box > :nth-child(6) > div.internal-grouping-01 > .body-compact-01" - ) - .should("exist") - .and("have.text", "Good standing"); - - cy.get("#workSafeBCNumber").should("exist"); - cy.get("#doingBusinessAs").should("exist"); - cy.get("#acronym").should("exist"); - }); - - describe("Scenario combinations", () => { - const scenarios = [ - { - scenarioName: "OK State - Corporation", - companySearch: "cmp", - companyCode: "C1231231", - showData: true, - showBirthdate: false, - showUnknowNotification: false, - showNotGoodStandingNotification: false, - showBcRegDownNotification: false, - showDuplicatedNotification: false, - type: "Corporation", - standing: "Good standing", - dba: "", - }, - { - scenarioName: "OK State - Corporation not found", - companySearch: "cnf", - companyCode: "C9999999", - showData: true, - showBirthdate: false, - showUnknowNotification: true, - showNotGoodStandingNotification: false, - showBcRegDownNotification: false, - showDuplicatedNotification: false, - type: "Corporation", - standing: "Unknown", - dba: "", - }, - { - scenarioName: "OK State - Sole Proprietorship, show birthdate", - companySearch: "spp", - companyCode: "FM123123", - showData: true, - showBirthdate: true, - showUnknowNotification: false, - showNotGoodStandingNotification: false, - showBcRegDownNotification: false, - showDuplicatedNotification: false, - type: "Sole proprietorship", - standing: "Good standing", - dba: "Soleprop", - }, - { - scenarioName: "OK State - Unsuported types for external", - companySearch: "llp", - companyCode: "LL123123", - showData: false, - showBirthdate: false, - showUnknowNotification: false, - showNotGoodStandingNotification: false, - showBcRegDownNotification: false, - type: "Limited liability partnership", - standing: "Unknown", - dba: "", - }, - { - scenarioName: "OK State - SP not owned by person", - companySearch: "spw", - companyCode: "FM7715744", - showData: true, - showBirthdate: true, - showUnknowNotification: false, - showNotGoodStandingNotification: false, - showBcRegDownNotification: false, - showDuplicatedNotification: false, - type: "Sole proprietorship", - standing: "Good standing", - dba: "Soleprop", - }, - { - scenarioName: "Failed state - Unknown standing", - companySearch: "uks", - companyCode: "C4566541", - showData: true, - showBirthdate: false, - showUnknowNotification: true, - showNotGoodStandingNotification: false, - showBcRegDownNotification: false, - showDuplicatedNotification: false, - type: "Corporation", - standing: "Unknown", - dba: "", - }, - { - scenarioName: "Failed state - BC Registry down", - companySearch: "bcd", - companyCode: "C7745745", - showData: false, - showBirthdate: false, - showUnknowNotification: false, - showNotGoodStandingNotification: false, - showBcRegDownNotification: true, - showDuplicatedNotification: false, - type: "Corporation", - standing: "Good Standing", - dba: "", - }, - { - scenarioName: "Failed state - Duplicated entry", - companySearch: "dup", - companyCode: "C7775745", - showData: true, - showBirthdate: false, - showUnknowNotification: true, - showNotGoodStandingNotification: false, - showBcRegDownNotification: false, - showDuplicatedNotification: true, - type: "Corporation", - standing: "Unknown", - dba: "", - }, - { - scenarioName: "Failed state - Not in good standing", - companySearch: "ngs", - companyCode: "C4443332", - showData: true, - showBirthdate: false, - showUnknowNotification: false, - showNotGoodStandingNotification: true, - showBcRegDownNotification: false, - type: "Corporation", - standing: "Not in good standing", - dba: "", - }, - ]; - - beforeEach(function () { - //The title contains some parameters that we need to extract - const params: string[] = this.currentTest.title - .split(":")[1] - .trim() - .replace(" should return ", " ") - .split(" "); - - const detailsCode = (code: string) => { - return code === "bcd" - ? 408 - : code === "dup" - ? 409 - : code === "cnf" - ? 404 - : 200; - }; - - //We need to intercept the client search for the scenario, as param 1 - cy.intercept("GET", `**/api/clients/name/${params[0]}`, { - statusCode: 200, - fixture: "clients/bcreg_ac_list2.json", - }).as("clientSearch"); - - //If the search is successful, we need to intercept the subsequent search that happens when the clie8nt is selected - if (detailsCode(params[0]) === 200) { - cy.fixture(`clients/bcreg_${params[1]}.json`, "utf-8") - .then((data) => { - cy.intercept( - "GET", - `**/api/clients/name/${encodeURIComponent(data.name)}`, - { - fixture: "clients/bcreg_ac_list2.json", - } - ).as("clientSearchEncoded"); - }) - .as("responseData"); - } - - if (detailsCode(params[0]) === 409) { - cy.intercept( - "GET", - `**/api/clients/name/${encodeURIComponent("Corporation 5")}`, + cy.fixture("clients/bcreg_ac_list2.json").then((data) => + data.forEach(element => cy.intercept("GET",`**/api/clients/name/${encodeURIComponent(element.name)}`, { fixture: "clients/bcreg_ac_list2.json", } - ).as("clientSearchEncodedToo"); - } + ) + ) + ); - if (detailsCode(params[0]) === 404) { - cy.intercept( - "GET", - `**/api/clients/name/${encodeURIComponent("Corporation 6")}`, + cy.fixture("clients/bcreg_ac_list3.json").then((data) => + data.forEach(element => cy.intercept("GET",`**/api/clients/name/${encodeURIComponent(element.name)}`, { - fixture: "clients/bcreg_ac_list2.json", + fixture: "clients/bcreg_ac_list3.json", } - ).as("clientSearchEncodedToo"); - } - - //We load the fixture beforehand due to the different content types and extensions based on the response - cy.fixture( - `clients/bcreg_${params[1]}.${ - detailsCode(params[0]) === 200 ? "json" : "txt" - }`, - "utf-8" - ).then((data) => { - cy.log("data", data); - cy.intercept("GET", `**/api/clients/${params[1]}`, { - statusCode: detailsCode(params[0]), - body: data, - headers: { - "content-type": - detailsCode(params[0]) !== 200 - ? "text/plain" - : "application/json", - }, - }).as("clientDetails"); - }); - }); - - scenarios.forEach((scenario) => { - it(`${scenario.scenarioName} : ${scenario.companySearch} should return ${scenario.companyCode}`, () => { - const formContent: FormDataDto = newFormDataDto(); - formContent.businessInformation.businessName = ""; - formContent.businessInformation.businessType = "BCR"; - - cy.mount(BcRegisteredClientInformationWizardStep, { - props: { - data: formContent, - active: true, - autofocus: false, - }, - }); - - // Initially, only the client name and the info notification should exist - cy.get("#businessName").should("exist"); - cy.get("cds-inline-notification").should("exist"); - - //Just a check to make sure the fields are not visible - cy.get(".read-only-box").should("not.exist"); - - cy.get("cds-inline-notification#bcRegistrySearchNotification").should( - "exist" - ); - - // Then, when a client is selected, the rest of the form should appear - cy.selectAutocompleteEntry( - "#businessName", - scenario.companySearch, - scenario.companyCode, - "@clientSearch" - ); - - if (scenario.showDuplicatedNotification) { - cy.get("#businessName") - .should("have.attr", "aria-invalid", "true") - .should("have.attr", "invalid-text", "Client already exists"); - - cy.get("#businessName").shadow().find("svg").should("exist"); - } - - cy.get("cds-inline-notification#bcRegistrySearchNotification").should( - "not.exist" - ); - - if (scenario.showBcRegDownNotification) { - cy.wait("@clientDetails"); - cy.wait(5000); - cy.get("cds-inline-notification#bcRegistryDownNotification").should( - "exist" - ); - } - - if (scenario.showData) { - const success = Object.entries(scenario) - .filter( - ([key, value]) => - key.startsWith("show") && key.endsWith("Notification") - ) - .map(([key, value]) => value) - .every((value) => value === false); - - cy.get( - ".read-only-box > cds-inline-notification#readOnlyNotification" - ).should( - success || scenario.showDuplicatedNotification - ? "exist" - : "not.exist" - ); - - cy.get(`.read-only-box > #legalType > .title-group-01 > .label-01`) - .should("exist") - .and("have.text", "Type"); - - cy.get(`.read-only-box > #legalType > .body-compact-01`) - .should("exist") - .and("have.text", scenario.type); - - cy.get( - `.read-only-box > #registrationNumber > .title-group-01 > .label-01` - ) - .should("exist") - .and("have.text", "Registration number"); - - cy.get(`.read-only-box > #registrationNumber > .body-compact-01`) - .should("exist") - .and("have.text", scenario.companyCode); - - if (scenario.showUnknowNotification) { - cy.get( - ".read-only-box > cds-inline-notification#unknownStandingNotification" - ).should("exist"); - //TODO: check the text and style maybe?! - } - - if (scenario.showNotGoodStandingNotification) { - cy.get( - ".read-only-box > cds-inline-notification#notGoodStandingNotification" - ).should("exist"); - //TODO: check the text and style maybe?! - } - - cy.get(`.read-only-box > #goodStanding > .title-group-01 > .label-01`) - .should("exist") - .and("have.text", "BC Registries standing"); - - cy.get( - `.read-only-box > #goodStanding > div.internal-grouping-01 > .body-compact-01` - ) - .should("exist") - .and("have.text", scenario.standing); - } - - if (scenario.showBirthdate) { - cy.get("#birthdate").should("be.visible"); - } + ) + ) + ); + }); - cy.get("#workSafeBCNumber").should("exist").and("have.value", ""); - cy.get("#doingBusinessAs").should(scenario.dba ? "not.exist" : "exist"); - cy.get("#acronym").should("exist").and("have.value", ""); - }); - }); + it('should render the component', () => { + loginAndNativateToStaffForm(); }); describe("Validation", () => { @@ -414,14 +52,6 @@ describe("", () => { fixture: "clients/bcreg_ac_list3.json", }).as("clientSearchCOR"); - cy.intercept( - "GET", - `**/api/clients/name/${encodeURIComponent("Existing Corporation 1")}`, - { - fixture: "clients/bcreg_ac_list3.json", - } - ).as("clientSearchEncodedCOR"); - cy.intercept("GET", `**/api/clients/C1234567`, { fixture: "clients/bcreg_C1234567.json", }).as("clientDetailsC1234567"); @@ -429,7 +59,7 @@ describe("", () => { // Long name corporation cy.intercept("GET", "**/api/clients/name/lon", { statusCode: 200, - fixture: "clients/bcreg_ac_list3.json", + fixture: "clients/bcreg_ac_list4.json", }).as("clientSearchLON"); cy.intercept( @@ -438,10 +68,31 @@ describe("", () => { "Existing Corporation with a super long name that should not be allowed here" )}`, { - fixture: "clients/bcreg_ac_list3.json", + fixture: "clients/bcreg_ac_list4.json", } ).as("clientSearchEncodedLON"); + cy.intercept("GET", "**/api/clients/name/all", { + statusCode: 200, + fixture: "clients/bcreg_ac_list4.json", + }).as("clientSearchALLLA1"); + cy.intercept("GET", "**/api/clients/name/alll", { + statusCode: 200, + fixture: "clients/bcreg_ac_list4.json", + }).as("clientSearchALLLA2"); + cy.intercept("GET", "**/api/clients/name/alllá", { + statusCode: 200, + fixture: "clients/bcreg_ac_list4.json", + }).as("clientSearchALLLA3"); + + cy.intercept( + "GET", + `**/api/clients/name/${encodeURIComponent("alllá")}`, + { + fixture: "clients/bcreg_ac_list4.json", + } + ).as("clientSearchEncodedALLLA4"); + cy.intercept("GET", `**/api/clients/C1231231`, { fixture: "clients/bcreg_C1231231.json", }).as("clientDetailsC1231231"); @@ -449,36 +100,16 @@ describe("", () => { // Existing Sole Proprietorship cy.intercept("GET", "**/api/clients/name/sol", { statusCode: 200, - fixture: "clients/bcreg_ac_list3.json", + fixture: "clients/bcreg_ac_list4.json", }).as("clientSearchSOL"); - - cy.intercept( - "GET", - `**/api/clients/name/${encodeURIComponent( - "Existing Sole Proprietorship 1" - )}`, - { - fixture: "clients/bcreg_ac_list3.json", - } - ).as("clientSearchEncodedSOL"); - + cy.intercept("GET", `**/api/clients/FM123456`, { fixture: "clients/bcreg_FM123456.json", }).as("clientDetailsFM123456"); + loginAndNativateToStaffForm(); }); - it("should validate the client name", () => { - const formContent: FormDataDto = newFormDataDto(); - formContent.businessInformation.businessName = ""; - formContent.businessInformation.businessType = "BCR"; - - cy.mount(BcRegisteredClientInformationWizardStep, { - props: { - data: formContent, - active: true, - autofocus: false, - }, - }); + it("should validate the client name", () => { cy.selectAutocompleteEntry( "#businessName", @@ -494,6 +125,8 @@ describe("", () => { "Client name cannot be empty" ); + cy.wait(2) + cy.selectAutocompleteEntry( "#businessName", "lon", @@ -504,29 +137,32 @@ describe("", () => { "#businessName", "The client name has a 60 character limit" ); + + cy.wait(2) cy.get("#businessName").shadow().find("div#selection-button").click(); - cy.fillFormEntry("#businessName", "lá"); - cy.get("div.frame-01").should("exist").click(); + cy.checkAutoCompleteErrorMessage( + "#businessName", + "Client name cannot be empty" + ); + cy.wait(2) + + cy.selectAutocompleteEntry( + "#businessName", + "alllá", + "FM999457", + "@clientSearchEncodedALLLA4" + ); + cy.wait(2) cy.checkAutoCompleteErrorMessage( "#businessName", "The client name can only contain: A-Z, a-z, 0-9, space or common symbols" ); + }); it("should validate work safe bc number", () => { - const formContent: FormDataDto = newFormDataDto(); - formContent.businessInformation.businessName = ""; - formContent.businessInformation.businessType = "BCR"; - - cy.mount(BcRegisteredClientInformationWizardStep, { - props: { - data: formContent, - active: true, - autofocus: false, - }, - }); cy.selectAutocompleteEntry( "#businessName", @@ -537,32 +173,27 @@ describe("", () => { cy.wait("@clientDetailsC1234567"); cy.get("#workSafeBCNumber").should("exist").and("have.value", ""); - cy.fillFormEntry("#workSafeBCNumber", "23456789012"); + cy.get("#workSafeBCNumber").shadow().find("input").clear(); + cy.fillFormEntry("#workSafeBCNumber", "potato"); cy.checkInputErrorMessage( "#workSafeBCNumber", - "The WorkSafeBC has a 6 character limit" + "WorkSafeBC number should contain only numbers" ); + + cy.wait(2) cy.get("#workSafeBCNumber").shadow().find("input").clear(); - cy.fillFormEntry("#workSafeBCNumber", "potato"); + cy.fillFormEntry("#workSafeBCNumber", "234567"); + cy.fillFormEntry("#doingBusinessAs", "Doing"); + cy.fillFormEntry("#workSafeBCNumber", "1"); cy.checkInputErrorMessage( "#workSafeBCNumber", - "WorkSafeBC number should contain only numbers" + "The WorkSafeBC has a 6 character limit" ); + }); it("should validate doing business as", () => { - const formContent: FormDataDto = newFormDataDto(); - formContent.businessInformation.businessName = ""; - formContent.businessInformation.businessType = "BCR"; - - cy.mount(BcRegisteredClientInformationWizardStep, { - props: { - data: formContent, - active: true, - autofocus: false, - }, - }); cy.selectAutocompleteEntry( "#businessName", @@ -588,17 +219,6 @@ describe("", () => { }); it("should validate acronym", () => { - const formContent: FormDataDto = newFormDataDto(); - formContent.businessInformation.businessName = ""; - formContent.businessInformation.businessType = "BCR"; - - cy.mount(BcRegisteredClientInformationWizardStep, { - props: { - data: formContent, - active: true, - autofocus: false, - }, - }); cy.selectAutocompleteEntry('#businessName', 'cor','C1234567','@clientSearchCOR'); cy.wait('@clientDetailsC1234567'); @@ -618,17 +238,6 @@ describe("", () => { }); it("should validate birthdate", () => { - const formContent: FormDataDto = newFormDataDto(); - formContent.businessInformation.businessName = ""; - formContent.businessInformation.businessType = "BCR"; - - cy.mount(BcRegisteredClientInformationWizardStep, { - props: { - data: formContent, - active: true, - autofocus: false, - }, - }); cy.selectAutocompleteEntry( "#businessName", @@ -686,4 +295,209 @@ describe("", () => { .and("include.text", "Date of birth must include a day"); }); }); -}); + + describe("Scenario combinations", () => { + + beforeEach(function () { + //The title contains some parameters that we need to extract + const params: string[] = this.currentTest.title + .split(":")[1] + .trim() + .replace(" should return ", " ") + .split(" "); + + const detailsCode = (code: string) => { + switch (code) { + case "bcd": + return 408; + case "dup": + return 409; + case "cnf": + return 404; + default: + return 200; + } + }; + + //We need to intercept the client search for the scenario, as param 1 + cy.intercept("GET", `**/api/clients/name/${params[0]}`, { + statusCode: 200, + fixture: "clients/bcreg_ac_list2.json", + }).as(`clientSearch${params[0]}`); + + //We load the fixture beforehand due to the different content types and extensions based on the response + cy.fixture( + `clients/bcreg_${params[1]}.${ + detailsCode(params[0]) === 200 ? "json" : "txt" + }`, + "utf-8" + ).then((data) => { + cy.log("data", data); + cy.intercept("GET", `**/api/clients/${params[1]}`, { + statusCode: detailsCode(params[0]), + body: data, + headers: { + "content-type": + detailsCode(params[0]) !== 200 + ? "text/plain" + : "application/json", + }, + }).as(`clientDetails${params[0]}`); + }); + loginAndNativateToStaffForm(); + }); + + testCases.forEach((scenario) => { + it(`${scenario.scenarioName} : ${scenario.companySearch} should return ${scenario.companyCode}`, () => { + // Initially, only the client name and the info notification should exist + cy.get("#businessName").should("exist"); + cy.get("cds-inline-notification").should("exist"); + + //Just a check to make sure the fields are not visible + cy.get(".read-only-box").should("not.exist"); + + cy.get("cds-inline-notification#bcRegistrySearchNotification").should( + "exist" + ); + + // Then, when a client is selected, the rest of the form should appear + cy.selectAutocompleteEntry( + "#businessName", + scenario.companySearch, + scenario.companyCode, + `@clientSearch${scenario.companySearch}` + ); + + cy.wait(`@clientDetails${scenario.companySearch}`); + + if (scenario.showDuplicatedNotification) { + cy.get("#businessName") + .should("have.attr", "aria-invalid", "true") + .should("have.attr", "invalid-text", "Client already exists"); + + cy.get("#businessName").shadow().find("svg").should("exist"); + } + + cy.get("cds-inline-notification#bcRegistrySearchNotification").should( + "not.exist" + ); + + if (scenario.showBcRegDownNotification) { + cy.wait(`@clientDetails${scenario.companySearch}`); + cy.wait(5000); + cy.get("cds-inline-notification#bcRegistryDownNotification").should( + "exist" + ); + } + + if (scenario.showData) { + const success = Object.entries(scenario) + .filter( + ([key, value]) => + key.startsWith("show") && key.endsWith("Notification") + ) + .map(([key, value]) => value) + .every((value) => value === false); + + cy.get( + ".read-only-box > cds-inline-notification#readOnlyNotification" + ).should( + success || scenario.showDuplicatedNotification + ? "exist" + : "not.exist" + ); + + cy.get(`.read-only-box > #legalType > .title-group-01 > .label-01`) + .should("exist") + .and("have.text", "Type"); + + cy.get(`.read-only-box > #legalType > .body-compact-01`) + .should("exist") + .and("have.text", scenario.type); + + cy.get( + `.read-only-box > #registrationNumber > .title-group-01 > .label-01` + ) + .should("exist") + .and("have.text", "Registration number"); + + cy.get(`.read-only-box > #registrationNumber > .body-compact-01`) + .should("exist") + .and("have.text", scenario.companyCode); + + if (scenario.showUnknowNotification) { + cy.get( + ".read-only-box > cds-inline-notification#unknownStandingNotification" + ).should("exist"); + //TODO: check the text and style maybe?! + } + + if (scenario.showNotGoodStandingNotification) { + cy.get( + ".read-only-box > cds-inline-notification#notGoodStandingNotification" + ).should("exist"); + //TODO: check the text and style maybe?! + } + + cy.get(`.read-only-box > #goodStanding > .title-group-01 > .label-01`) + .should("exist") + .and("have.text", "BC Registries standing"); + + cy.get( + `.read-only-box > #goodStanding > div.internal-grouping-01 > .body-compact-01` + ) + .should("exist") + .and("have.text", scenario.standing); + } + + if (scenario.showBirthdate) { + cy.get("#birthdate").should("be.visible"); + } + + if(scenario.showNotOwnedByPersonError){ + cy.get("#businessName") + .should("have.attr", "aria-invalid", "true") + .should("have.attr", "invalid-text", "This sole proprietor is not owned by a person"); + + cy.get("#businessName").shadow().find("svg").should("exist"); + } + + cy.get("#workSafeBCNumber").should("exist").and("have.value", ""); + cy.get("#doingBusinessAs").should(scenario.dba ? "not.exist" : "exist"); + cy.get("#acronym").should("exist").and("have.value", ""); + }); + }); + + }); + + const loginAndNativateToStaffForm = () => { + cy.visit("/"); + + cy.get("#landing-title").should( + "contain", + "Forests Client Management System" + ); + + cy.get("#landing-subtitle").should( + "contain", + "Create and manage client accounts" + ); + + cy.login("uattest@gov.bc.ca", "Uat Test", "idir", { + given_name: "James", + family_name: "Baxter", + "cognito:groups": ["CLIENT_ADMIN"], + }); + + cy.wait("@getSubmissions"); + + // Check if the Create client button is visible + cy.get("#menu-list-staff-form").should("be.visible").click(); + + cy.get("h1").should("be.visible").should("contain", " Create client "); + + cy.get("#clientType").should("be.visible").and("have.value", ""); + cy.selectFormEntry("#clientType", "BC registered business", false); + }; + +}); \ No newline at end of file diff --git a/frontend/cypress/fixtures/clients/bcreg_C1231231.json b/frontend/cypress/fixtures/clients/bcreg_C1231231.json index 1926596826..190ccac1fb 100644 --- a/frontend/cypress/fixtures/clients/bcreg_C1231231.json +++ b/frontend/cypress/fixtures/clients/bcreg_C1231231.json @@ -29,5 +29,6 @@ "phoneNumber": null, "email": null } - ] + ], + "isOwnedByPerson": false } \ No newline at end of file diff --git a/frontend/cypress/fixtures/clients/bcreg_C1234567.json b/frontend/cypress/fixtures/clients/bcreg_C1234567.json index 86e853f5da..67947182dd 100644 --- a/frontend/cypress/fixtures/clients/bcreg_C1234567.json +++ b/frontend/cypress/fixtures/clients/bcreg_C1234567.json @@ -29,5 +29,6 @@ "phoneNumber": null, "email": null } - ] + ], + "isOwnedByPerson": false } \ No newline at end of file diff --git a/frontend/cypress/fixtures/clients/bcreg_C4443332.json b/frontend/cypress/fixtures/clients/bcreg_C4443332.json index 4dfa33d704..b9ea3d0b34 100644 --- a/frontend/cypress/fixtures/clients/bcreg_C4443332.json +++ b/frontend/cypress/fixtures/clients/bcreg_C4443332.json @@ -29,5 +29,6 @@ "phoneNumber": null, "email": null } - ] + ], + "isOwnedByPerson": false } \ No newline at end of file diff --git a/frontend/cypress/fixtures/clients/bcreg_C4566541.json b/frontend/cypress/fixtures/clients/bcreg_C4566541.json index 502e5d7b46..931d3f522c 100644 --- a/frontend/cypress/fixtures/clients/bcreg_C4566541.json +++ b/frontend/cypress/fixtures/clients/bcreg_C4566541.json @@ -28,5 +28,6 @@ "phoneNumber": null, "email": null } - ] + ], + "isOwnedByPerson": false } \ No newline at end of file diff --git a/frontend/cypress/fixtures/clients/bcreg_C7775745.json b/frontend/cypress/fixtures/clients/bcreg_C7775745.json index 0f047d68df..d7112d5991 100644 --- a/frontend/cypress/fixtures/clients/bcreg_C7775745.json +++ b/frontend/cypress/fixtures/clients/bcreg_C7775745.json @@ -1,3 +1,4 @@ { - "name": "Corporation 5" + "name": "Corporation 5", + "isOwnedByPerson": false } \ No newline at end of file diff --git a/frontend/cypress/fixtures/clients/bcreg_FM123123.json b/frontend/cypress/fixtures/clients/bcreg_FM123123.json index e729285033..a01f7fe490 100644 --- a/frontend/cypress/fixtures/clients/bcreg_FM123123.json +++ b/frontend/cypress/fixtures/clients/bcreg_FM123123.json @@ -29,5 +29,6 @@ "phoneNumber": null, "email": null } - ] + ], + "isOwnedByPerson": true } \ No newline at end of file diff --git a/frontend/cypress/fixtures/clients/bcreg_FM123456.json b/frontend/cypress/fixtures/clients/bcreg_FM123456.json index e729285033..a01f7fe490 100644 --- a/frontend/cypress/fixtures/clients/bcreg_FM123456.json +++ b/frontend/cypress/fixtures/clients/bcreg_FM123456.json @@ -29,5 +29,6 @@ "phoneNumber": null, "email": null } - ] + ], + "isOwnedByPerson": true } \ No newline at end of file diff --git a/frontend/cypress/fixtures/clients/bcreg_FM7715744.json b/frontend/cypress/fixtures/clients/bcreg_FM7715744.json index 15fdf314c0..6059da5f3f 100644 --- a/frontend/cypress/fixtures/clients/bcreg_FM7715744.json +++ b/frontend/cypress/fixtures/clients/bcreg_FM7715744.json @@ -29,5 +29,6 @@ "phoneNumber": null, "email": null } - ] + ], + "isOwnedByPerson": false } \ No newline at end of file diff --git a/frontend/cypress/fixtures/clients/bcreg_FM999457.json b/frontend/cypress/fixtures/clients/bcreg_FM999457.json new file mode 100644 index 0000000000..4645e5fb90 --- /dev/null +++ b/frontend/cypress/fixtures/clients/bcreg_FM999457.json @@ -0,0 +1,34 @@ +{ + "name": "Koalllá", + "id": "FM999457", + "goodStanding": true, + "addresses": [ + { + "streetAddress": "78417 Fulton Place", + "country": { + "value": "CA", + "text": "Canada" + }, + "province": { + "value": "AB", + "text": "Alberta" + }, + "city": "Rocky Mountain House", + "postalCode": "T4T4T4", + "locationName": "Mailing address" + } + ], + "contacts": [ + { + "contactType": { + "value": "DI", + "text": null + }, + "firstName": "Brig", + "lastName": "Kettlestringes", + "phoneNumber": null, + "email": null + } + ], + "isOwnedByPerson": false +} \ No newline at end of file diff --git a/frontend/cypress/fixtures/clients/bcreg_LL123123.json b/frontend/cypress/fixtures/clients/bcreg_LL123123.json index bcabd26728..26c298fb9f 100644 --- a/frontend/cypress/fixtures/clients/bcreg_LL123123.json +++ b/frontend/cypress/fixtures/clients/bcreg_LL123123.json @@ -29,5 +29,6 @@ "phoneNumber": null, "email": null } - ] + ], + "isOwnedByPerson": true } \ No newline at end of file diff --git a/frontend/cypress/fixtures/clients/bcreg_ac_list4.json b/frontend/cypress/fixtures/clients/bcreg_ac_list4.json new file mode 100644 index 0000000000..8894859b62 --- /dev/null +++ b/frontend/cypress/fixtures/clients/bcreg_ac_list4.json @@ -0,0 +1,26 @@ +[ + { + "code": "C1234567", + "name": "Existing Corporation 1", + "status": "ACTIVE", + "legalType": "C" + }, + { + "code": "C1231231", + "name": "Existing Corporation with a super long name that should not be allowed here", + "status": "ACTIVE", + "legalType": "C" + }, + { + "code": "FM123456", + "name": "Existing Sole Proprietorship 1", + "status": "ACTIVE", + "legalType": "SP" + }, + { + "code": "FM999457", + "name": "Koalllá", + "status": "ACTIVE", + "legalType": "SP" + } +] diff --git a/frontend/cypress/fixtures/staff/bcregisteredscenarios.json b/frontend/cypress/fixtures/staff/bcregisteredscenarios.json new file mode 100644 index 0000000000..bf5b9a1ef9 --- /dev/null +++ b/frontend/cypress/fixtures/staff/bcregisteredscenarios.json @@ -0,0 +1,133 @@ +[ + { + "scenarioName": "Failed state - Duplicated entry", + "companySearch": "dup", + "companyCode": "C7775745", + "showData": true, + "showBirthdate": false, + "showUnknowNotification": true, + "showNotGoodStandingNotification": false, + "showBcRegDownNotification": false, + "showDuplicatedNotification": true, + "showNotOwnedByPersonError": false, + "type": "Corporation", + "standing": "Unknown", + "dba": "" + }, + { + "scenarioName": "OK State - Sole Proprietorship, show birthdate", + "companySearch": "spp", + "companyCode": "FM123123", + "showData": true, + "showBirthdate": true, + "showUnknowNotification": false, + "showNotGoodStandingNotification": false, + "showBcRegDownNotification": false, + "showDuplicatedNotification": false, + "showNotOwnedByPersonError": false, + "type": "Sole proprietorship", + "standing": "Good standing", + "dba": "Soleprop" + }, + { + "scenarioName": "Failed state - BC Registry down", + "companySearch": "bcd", + "companyCode": "C7745745", + "showData": false, + "showBirthdate": false, + "showUnknowNotification": false, + "showNotGoodStandingNotification": false, + "showBcRegDownNotification": true, + "showDuplicatedNotification": false, + "showNotOwnedByPersonError": false, + "type": "Corporation", + "standing": "Good Standing", + "dba": "" + }, + { + "scenarioName": "Failed state - Not in good standing", + "companySearch": "ngs", + "companyCode": "C4443332", + "showData": true, + "showBirthdate": false, + "showUnknowNotification": false, + "showNotGoodStandingNotification": true, + "showBcRegDownNotification": false, + "type": "Corporation", + "standing": "Not in good standing", + "dba": "" + }, + { + "scenarioName": "OK State - Corporation", + "companySearch": "cmp", + "companyCode": "C1231231", + "showData": true, + "showBirthdate": false, + "showUnknowNotification": false, + "showNotGoodStandingNotification": false, + "showBcRegDownNotification": false, + "showDuplicatedNotification": false, + "showNotOwnedByPersonError": false, + "type": "Corporation", + "standing": "Good standing", + "dba": "" + }, + { + "scenarioName": "OK State - Corporation not found", + "companySearch": "cnf", + "companyCode": "C9999999", + "showData": true, + "showBirthdate": false, + "showUnknowNotification": true, + "showNotGoodStandingNotification": false, + "showBcRegDownNotification": false, + "showDuplicatedNotification": false, + "showNotOwnedByPersonError": false, + "type": "Corporation", + "standing": "Unknown", + "dba": "" + }, + { + "scenarioName": "OK State - Unsuported types for external", + "companySearch": "llp", + "companyCode": "LL123123", + "showData": false, + "showBirthdate": false, + "showUnknowNotification": false, + "showNotGoodStandingNotification": false, + "showBcRegDownNotification": false, + "type": "Limited liability partnership", + "standing": "Unknown", + "dba": "" + }, + { + "scenarioName": "Failed state - Unknown standing", + "companySearch": "uks", + "companyCode": "C4566541", + "showData": true, + "showBirthdate": false, + "showUnknowNotification": true, + "showNotGoodStandingNotification": false, + "showBcRegDownNotification": false, + "showDuplicatedNotification": false, + "showNotOwnedByPersonError": false, + "type": "Corporation", + "standing": "Unknown", + "dba": "" + }, + { + "scenarioName": "Failed state - SP not owned by person", + "companySearch": "spw", + "companyCode": "FM7715744", + "showData": true, + "showBirthdate": true, + "showUnknowNotification": false, + "showNotGoodStandingNotification": false, + "showBcRegDownNotification": false, + "showDuplicatedNotification": false, + "showNotOwnedByPersonError": true, + "type": "Sole proprietorship", + "standing": "Good standing", + "dba": "Soleprop" + } +] \ No newline at end of file diff --git a/frontend/src/components/grouping/FuzzyMatchNotificationGroupingComponent.vue b/frontend/src/components/grouping/FuzzyMatchNotificationGroupingComponent.vue index 9fca1617b8..f17901ac1e 100644 --- a/frontend/src/components/grouping/FuzzyMatchNotificationGroupingComponent.vue +++ b/frontend/src/components/grouping/FuzzyMatchNotificationGroupingComponent.vue @@ -36,8 +36,11 @@ defineExpose({ fuzzyMatchedError, }); +const customError = ref<{title?:string, message?: string}>({}); + const fieldNameToDescription : Record = { "businessInformation.businessName": "client name", + "businessInformation.notOwnedByPerson": "client name", "businessInformation.registrationNumber": "registration number", "businessInformation.individual": "name and birthdate", "businessInformation.individualAndDocument": "name, birthdate and identification number", @@ -72,6 +75,7 @@ const fieldNameToDescription : Record = { }; const fieldNameToNamingGroups: Record = { + "businessInformation.notOwnedByPerson": ["businessInformation.businessName"], "businessInformation.businessName": ["businessInformation.businessName"], "businessInformation.registrationNumber": ["businessInformation.businessName"], "businessInformation.federalId": ["businessInformation.businessName"], @@ -114,6 +118,7 @@ const fieldNameToNamingGroups: Record = { }; const fieldNameToLabel: Record = { + "businessInformation.notOwnedByPerson": "client", "businessInformation.individual": "name and date of birth", "businessInformation.individualAndDocument": "name, date of birth and ID number", "businessInformation.clientIdentification": "ID type and ID number", @@ -229,9 +234,10 @@ const clearNotification = () => { fuzzyMatchedError.value.show = false; fuzzyMatchedError.value.fuzzy = false; fuzzyMatchedError.value.matches = []; + customError.value = {}; }; -const handleFuzzyErrorMessage = (event: FuzzyMatcherEvent | undefined, _payload?: any) => { +const handleFuzzyErrorMessage = (event: FuzzyMatcherEvent | undefined, payload?: any) => { if (!event) { clearNotification(); return; @@ -245,6 +251,9 @@ const handleFuzzyErrorMessage = (event: FuzzyMatcherEvent | undefined, _payload? fuzzyMatchedError.value.fuzzy = true; fuzzyMatchedError.value.matches = []; + if(payload && payload.title && payload.message){ + customError.value = payload; + } for (const rawMatch of event.matches.sort((a, b) => a.fuzzy ? 1 : -1)) { @@ -292,25 +301,26 @@ fuzzyBus.on(handleFuzzyErrorMessage); hide-close-button="true" open="true" :kind="fuzzyMatchedError.fuzzy ? 'warning' : 'error'" - :title="fuzzyMatchedError.fuzzy ? 'Possible matching records found' : 'Client already exists'" + :title="customError.title || (fuzzyMatchedError.fuzzy ? 'Possible matching records found' : 'Client already exists')" >
+ {{ customError.message }} - + Review them in the Client Management System to determine if you should create a new client. - + It looks like ”{{ businessName }}” has client number . - + You must inform the applicant of their number.
diff --git a/frontend/src/dto/ApplyClientNumberDto.ts b/frontend/src/dto/ApplyClientNumberDto.ts index 4ae6281fe0..1e92cd7de7 100644 --- a/frontend/src/dto/ApplyClientNumberDto.ts +++ b/frontend/src/dto/ApplyClientNumberDto.ts @@ -63,6 +63,7 @@ export interface ForestClientDetailsDto { goodStanding: boolean; addresses: Address[]; contacts: Contact[]; + isOwnedByPerson: boolean; } export interface FirstNationDetailsDto { diff --git a/frontend/src/pages/staffform/BcRegisteredClientInformationWizardStep.vue b/frontend/src/pages/staffform/BcRegisteredClientInformationWizardStep.vue index 2a5963df6c..9400a6e7e4 100644 --- a/frontend/src/pages/staffform/BcRegisteredClientInformationWizardStep.vue +++ b/frontend/src/pages/staffform/BcRegisteredClientInformationWizardStep.vue @@ -207,6 +207,45 @@ watch([detailsData], () => { fuzzyBus.emit({ id: "", matches: [] }); const forestClientDetails: ForestClientDetailsDto = detailsData.value; + if ( + formData.value.businessInformation.clientType === "RSP" && + !forestClientDetails.isOwnedByPerson + ) { + errorBus.emit( + [ + { + fieldId: "businessInformation.businessName", + fieldName: "Client name", + errorMsg: "This sole proprietor is not owned by a person", + }, + ], + { + skipNotification: true, + } + ); + + fuzzyBus.emit( + { + id: "global", + matches: [ + { + field: "businessInformation.notOwnedByPerson", + match: "", + fuzzy: false, + }, + ], + }, + { + title: "Sole proprietor not owned by a person", + message: + 'This sole proprietor is not owned by a person. Please select the "Unregistered company" client type to proceed.', + } + ); + validation.soleproprietor = false; + } else { + validation.soleproprietor = true; + } + if (formData.value.businessInformation.clientType === "RSP") { formData.value.businessInformation.doingBusinessAs = forestClientDetails.name;