diff --git a/src/constants/enums.ts b/src/constants/enums.ts index 848cb76b..dc997052 100644 --- a/src/constants/enums.ts +++ b/src/constants/enums.ts @@ -1,7 +1,9 @@ import * as FALLBACK_TO_LEGACY_DATA from './enums/fallbackToLegacyData'; +import * as GEOSPATIAL from './enums/geospatial'; import * as PRODUCTS from './enums/products'; export const ENUMS = { PRODUCTS: PRODUCTS.QueryParamProductsEnum, FALLBACK_TO_LEGACY_DATA: FALLBACK_TO_LEGACY_DATA.FallbackToLegacyDataEnum, + GEOSPATIAL_COUNTRIES: GEOSPATIAL.GeospatialCountriesEnum, }; diff --git a/src/constants/enums/geospatial.ts b/src/constants/enums/geospatial.ts new file mode 100644 index 00000000..f181289d --- /dev/null +++ b/src/constants/enums/geospatial.ts @@ -0,0 +1,6 @@ +export enum GeospatialCountriesEnum { + E = 'England', + S = 'Scotland', + W = 'Wales', + N = 'Northern Ireland', +} diff --git a/src/constants/geospatial.constant.ts b/src/constants/geospatial.constant.ts new file mode 100644 index 00000000..08bd74c2 --- /dev/null +++ b/src/constants/geospatial.constant.ts @@ -0,0 +1,9 @@ +export const GEOSPATIAL = { + DEFAULT: { + RESULT_LANGUAGE: 'EN', + DATASET: 'DPA', + }, + EXAMPLES: { + POSTCODE: 'SW1A 2AQ', + }, +}; diff --git a/src/constants/index.ts b/src/constants/index.ts index 7bd70773..dd7a98e7 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -9,6 +9,7 @@ * 5. Customers * 6. Strings to redact * 7. Strings locations to redact + * 8. Module geospatial */ export * from './auth.constant'; @@ -16,6 +17,7 @@ export * from './customers.constant'; export * from './database-name.constant'; export * from './date.constant'; export * from './enums'; +export * from './geospatial.constant'; export * from './products.constant'; export * from './redact-strings.constant'; export * from './redact-strings-paths.constant'; diff --git a/src/helper-modules/ordnance-survey/known-errors.ts b/src/helper-modules/ordnance-survey/known-errors.ts index 5684be7d..48c9d029 100644 --- a/src/helper-modules/ordnance-survey/known-errors.ts +++ b/src/helper-modules/ordnance-survey/known-errors.ts @@ -5,9 +5,9 @@ export type KnownErrors = KnownError[]; type KnownError = { caseInsensitiveSubstringToFind: string; throwError: (error: AxiosError) => never }; -export const getCustomersNotFoundKnownOrdnanceSurveyError = (): KnownError => ({ - caseInsensitiveSubstringToFind: 'Company registration not found', +export const getAddressNotFoundKnownOrdnanceSurveyError = (): KnownError => ({ + caseInsensitiveSubstringToFind: 'Address not found', throwError: (error) => { - throw new NotFoundException('Customer not found.', error); + throw new NotFoundException('Address not found.', error); }, }); diff --git a/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts b/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts index 6ed18f36..e3cfceca 100644 --- a/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts +++ b/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts @@ -7,6 +7,8 @@ import { of, throwError } from 'rxjs'; import expectedResponse = require('./examples/example-response-for-search-places-v1-postcode.json'); import noResultsResponse = require('./examples/example-response-for-search-places-v1-postcode-no-results.json'); +import { GEOSPATIAL } from '@ukef/constants'; + import { OrdnanceSurveyException } from './exception/ordnance-survey.exception'; import { OrdnanceSurveyService } from './ordnance-survey.service'; @@ -17,7 +19,7 @@ describe('OrdnanceSurveyService', () => { let configServiceGet: jest.Mock; let service: OrdnanceSurveyService; - const testPostcode = 'W1A 1AA'; + const testPostcode = GEOSPATIAL.EXAMPLES.POSTCODE; const testKey = valueGenerator.string({ length: 10 }); const basePath = '/search/places/v1/postcode'; @@ -34,7 +36,7 @@ describe('OrdnanceSurveyService', () => { }); describe('getAddressesByPostcode', () => { - const expectedPath = `${basePath}?postcode=${encodeURIComponent(testPostcode)}&key=${encodeURIComponent(testKey)}`; + const expectedPath = `${basePath}?postcode=${encodeURIComponent(testPostcode)}&lr=EN&key=${encodeURIComponent(testKey)}`; const expectedHttpServiceGetArgs: [string, object] = [expectedPath, { headers: { 'Content-Type': 'application/json' } }]; @@ -67,7 +69,7 @@ describe('OrdnanceSurveyService', () => { expectedUrlQueryPart: '?postcode=W1A1AA', }, ])('call Ordnance Survey API with correct and safe query parameters "$expectedUrlQueryPart"', async ({ postcode, expectedUrlQueryPart }) => { - const expectedPath = `${basePath}${expectedUrlQueryPart}&key=${encodeURIComponent(testKey)}`; + const expectedPath = `${basePath}${expectedUrlQueryPart}&lr=EN&key=${encodeURIComponent(testKey)}`; const expectedHttpServiceGetArgs: [string, object] = [expectedPath, { headers: { 'Content-Type': 'application/json' } }]; when(httpServiceGet) diff --git a/src/helper-modules/ordnance-survey/ordnance-survey.service.ts b/src/helper-modules/ordnance-survey/ordnance-survey.service.ts index 5464166e..dfa35330 100644 --- a/src/helper-modules/ordnance-survey/ordnance-survey.service.ts +++ b/src/helper-modules/ordnance-survey/ordnance-survey.service.ts @@ -2,6 +2,7 @@ import { HttpService } from '@nestjs/axios'; import { Injectable } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { KEY as ORDNANCE_SURVEY_CONFIG_KEY, OrdnanceSurveyConfig } from '@ukef/config/ordnance-survey.config'; +import { GEOSPATIAL } from '@ukef/constants'; import { HttpClient } from '@ukef/modules/http/http.client'; import { GetAddressResponse } from './dto/get-addresses-response.dto'; @@ -20,7 +21,7 @@ export class OrdnanceSurveyService { } async getAddressesByPostcode(postcode): Promise { - const path = `/search/places/v1/postcode?postcode=${encodeURIComponent(postcode)}&key=${encodeURIComponent(this.key)}`; + const path = `/search/places/v1/postcode?postcode=${encodeURIComponent(postcode)}&lr=${GEOSPATIAL.DEFAULT.RESULT_LANGUAGE}&key=${encodeURIComponent(this.key)}`; const { data } = await this.httpClient.get({ path, diff --git a/src/modules/geospatial/dto/get-address-by-postcode-query.dto.ts b/src/modules/geospatial/dto/get-address-by-postcode-query.dto.ts index 698dbe25..6202fdd1 100644 --- a/src/modules/geospatial/dto/get-address-by-postcode-query.dto.ts +++ b/src/modules/geospatial/dto/get-address-by-postcode-query.dto.ts @@ -1,11 +1,12 @@ import { ApiProperty } from '@nestjs/swagger'; +import { GEOSPATIAL } from '@ukef/constants'; import { Matches, MaxLength, MinLength } from 'class-validator'; const UK_POSTCODE = /^[A-Za-z]{1,2}[\dRr][\dA-Za-z]?\s?\d[ABD-HJLNP-UW-Zabd-hjlnp-uw-z]{2}$/; export class GetAddressByPostcodeQueryDto { @ApiProperty({ - example: 'SW1A 2AQ', + example: GEOSPATIAL.EXAMPLES.POSTCODE, description: 'Postcode to search for', }) @MinLength(5) diff --git a/src/modules/geospatial/dto/get-search-addresses-response.dto.ts b/src/modules/geospatial/dto/get-search-addresses-response.dto.ts index d4b84090..5ba8a8c7 100644 --- a/src/modules/geospatial/dto/get-search-addresses-response.dto.ts +++ b/src/modules/geospatial/dto/get-search-addresses-response.dto.ts @@ -1,4 +1,5 @@ import { ApiProperty } from '@nestjs/swagger'; +import { ENUMS, GEOSPATIAL } from '@ukef/constants'; export type GetSearchAddressesResponse = GetSearchAddressesResponseItem[]; @@ -35,13 +36,14 @@ export class GetSearchAddressesResponseItem { @ApiProperty({ description: 'Postcode', - example: 'SW1A 2AQ', + example: GEOSPATIAL.EXAMPLES.POSTCODE, }) readonly postalCode: string | null; @ApiProperty({ description: 'Country of address record', - example: null, + example: ENUMS.GEOSPATIAL_COUNTRIES.E, + enum: ENUMS.GEOSPATIAL_COUNTRIES, }) readonly country: string | null; } diff --git a/src/modules/geospatial/geospatial.controller.ts b/src/modules/geospatial/geospatial.controller.ts index 4c25561a..5c210dc5 100644 --- a/src/modules/geospatial/geospatial.controller.ts +++ b/src/modules/geospatial/geospatial.controller.ts @@ -16,8 +16,7 @@ export class GeospatialController { }) @ApiResponse({ status: 200, - description: - 'AddressBase® Premium Basic Land and Property Units (BLPUs) can reference two types of address and with the OS Places API it is possible to search for one at a time, or both. These are the Delivery Point Address (DPA) and the Land and Property Identifier (LPI).', + description: 'Returns addresses from Ordanance survey Delivery Point Address (DPA) system.', type: [GetSearchAddressesResponseItem], }) @ApiNotFoundResponse({ diff --git a/src/modules/geospatial/geospatial.service.ts b/src/modules/geospatial/geospatial.service.ts index af45adab..ca4f4a69 100644 --- a/src/modules/geospatial/geospatial.service.ts +++ b/src/modules/geospatial/geospatial.service.ts @@ -1,4 +1,5 @@ import { Injectable } from '@nestjs/common'; +import { ENUMS } from '@ukef/constants'; import { OrdnanceSurveyService } from '@ukef/helper-modules/ordnance-survey/ordnance-survey.service'; import { GetSearchAddressesResponse } from './dto/get-search-addresses-response.dto'; @@ -12,19 +13,17 @@ export class GeospatialService { const response = await this.ordnanceSurveyService.getAddressesByPostcode(postcode); response.results.forEach((item) => { - // if (item.DPA.LANGUAGE === (req.query.language ? req.query.language : 'EN')) { // Ordnance survey sends duplicated results with the welsh version too via 'CY' - if (item.DPA.LANGUAGE === 'EN') { - addresses.push({ - organisationName: item.DPA.ORGANISATION_NAME || null, - addressLine1: `${item.DPA.BUILDING_NAME || ''} ${item.DPA.BUILDING_NUMBER || ''} ${item.DPA.THOROUGHFARE_NAME || ''}`.trim(), - addressLine2: item.DPA.DEPENDENT_LOCALITY || null, - addressLine3: null, // keys to match registered Address as requested, but not available in OS Places - locality: item.DPA.POST_TOWN || null, - postalCode: item.DPA.POSTCODE || null, - country: null, // keys to match registered Address as requested, but not available in OS Places - }); - } + const item_data = item[Object.keys(item)[0]]; + addresses.push({ + organisationName: item_data.ORGANISATION_NAME || null, + addressLine1: `${item_data.BUILDING_NAME || ''} ${item_data.BUILDING_NUMBER || ''} ${item_data.THOROUGHFARE_NAME || ''}`.trim(), + addressLine2: item_data.DEPENDENT_LOCALITY || null, + addressLine3: null, + locality: item_data.POST_TOWN || null, + postalCode: item_data.POSTCODE || null, + country: ENUMS.GEOSPATIAL_COUNTRIES[item_data.COUNTRY_CODE], + }); }); return addresses;