diff --git a/app/data-sources/rural-payments/RuralPaymentsCustomer.js b/app/data-sources/rural-payments/RuralPaymentsCustomer.js index 2ce33be7..7ed3fc22 100644 --- a/app/data-sources/rural-payments/RuralPaymentsCustomer.js +++ b/app/data-sources/rural-payments/RuralPaymentsCustomer.js @@ -71,6 +71,12 @@ export class RuralPaymentsCustomer extends RuralPayments { return response._data } + async customerEmailExistsByEmailAddress(emailAddress) { + const response = await this.get(`person/${emailAddress}/validateEmail`) + + return response._data + } + async getPersonBusinessesByPersonId(personId) { const personBusinessSummaries = await this.get( // Currently requires and empty search parameter or it returns 500 error diff --git a/app/graphql/resolvers/customer/query.js b/app/graphql/resolvers/customer/query.js index cfd739e4..2a141f87 100644 --- a/app/graphql/resolvers/customer/query.js +++ b/app/graphql/resolvers/customer/query.js @@ -5,5 +5,15 @@ export const Query = { const personId = await retrievePersonIdByCRN(crn, dataSources) return { crn, personId } + }, + + async customerEmail(__, { emailAddress }, { dataSources }) { + const results = + await dataSources.ruralPaymentsCustomer.customerEmailExistsByEmailAddress(emailAddress) + + return { + emailAddress, + addressInUse: results.emailDuplicated + } } } diff --git a/app/graphql/types/customer/customer.gql b/app/graphql/types/customer/customer.gql index 9ce874fa..2efb4704 100644 --- a/app/graphql/types/customer/customer.gql +++ b/app/graphql/types/customer/customer.gql @@ -190,3 +190,20 @@ type CustomerBusiness { """ permissionGroups: [ActivePermissionGroup] @on @excludeFromList } + +""" +Customer email details. + +Data source: Rural Payments Portal +""" +type CustomerEmail { + """ + The email address. + """ + emailAddress: String! + + """ + Indicates if the address is already associated with a customer + """ + addressInUse: Boolean! +} diff --git a/app/graphql/types/customer/email-exists.gql b/app/graphql/types/customer/email-exists.gql new file mode 100644 index 00000000..234edd49 --- /dev/null +++ b/app/graphql/types/customer/email-exists.gql @@ -0,0 +1,10 @@ +extend type Query { + """ + Checks whether an email address already exists in the system. + + Data source: Rural Payments Portal + """ + emailExists(emailAddress: String!): Boolean + @on + @auth(requires: [CONSOLIDATED_VIEW, SINGLE_FRONT_DOOR]) +} diff --git a/app/graphql/types/customer/query.gql b/app/graphql/types/customer/query.gql index 892301f0..05d1a2ee 100644 --- a/app/graphql/types/customer/query.gql +++ b/app/graphql/types/customer/query.gql @@ -2,4 +2,11 @@ extend type Query { customer(crn: ID!): Customer @on @auth(requires: [CONSOLIDATED_VIEW, SINGLE_FRONT_DOOR, SFI_REFORM]) + + """ + Checks whether an email address already exists in the system. + + Data source: Rural Payments Portal + """ + customerEmail(emailAddress: String!): CustomerEmail @on @auth(requires: [SINGLE_FRONT_DOOR]) } diff --git a/package.json b/package.json index f2ce7fda..e89bec76 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fcp-dal-api", - "version": "2.2.1", + "version": "2.3.0", "description": "Customer Registry GraphQL Service", "homepage": "https://github.com/DEFRA/fcp-data-access-layer-api", "main": "app/index.js", diff --git a/test/graphql/full-schema.gql b/test/graphql/full-schema.gql index 0742b446..c323fcdc 100644 --- a/test/graphql/full-schema.gql +++ b/test/graphql/full-schema.gql @@ -2,6 +2,7 @@ type Query { business(sbi: ID!): Business customer(crn: ID!): Customer permissionGroups: [PermissionGroup] + customerEmail(emailAddress: String!): Boolean } type Mutation { diff --git a/test/graphql/partial-schema.gql b/test/graphql/partial-schema.gql index ab22e55c..861165e8 100644 --- a/test/graphql/partial-schema.gql +++ b/test/graphql/partial-schema.gql @@ -2,6 +2,7 @@ type Query { business(sbi: ID!): Business customer(crn: ID!): Customer permissionGroups: [PermissionGroup] + customerEmail(emailAddress: String!): Boolean } type Phone { diff --git a/test/unit/data-sources/rural-payments/rural-payments-customer.test.js b/test/unit/data-sources/rural-payments/rural-payments-customer.test.js index a9afdde0..88c935bb 100644 --- a/test/unit/data-sources/rural-payments/rural-payments-customer.test.js +++ b/test/unit/data-sources/rural-payments/rural-payments-customer.test.js @@ -240,4 +240,22 @@ describe('Rural Payments Customer', () => { }) expect(httpGet).toHaveBeenCalledTimes(1) }) + + test('should return emailDuplicated true when email already exists', async () => { + httpGet.mockImplementationOnce(async () => ({ _data: { emailDuplicated: true } })) + + const result = await ruralPaymentsCustomer.customerEmailExistsByEmailAddress('test@example.com') + + expect(result).toEqual({ emailDuplicated: true }) + expect(httpGet).toHaveBeenCalledWith('person/test@example.com/validateEmail') + }) + + test('should return emailDuplicated false when email does not exist', async () => { + httpGet.mockImplementationOnce(async () => ({ _data: { emailDuplicated: false } })) + + const result = await ruralPaymentsCustomer.customerEmailExistsByEmailAddress('new@example.com') + + expect(result).toEqual({ emailDuplicated: false }) + expect(httpGet).toHaveBeenCalledWith('person/new@example.com/validateEmail') + }) }) diff --git a/test/unit/resolvers/customer/customer.test.js b/test/unit/resolvers/customer/customer.test.js index 49ffd13d..2a923e1a 100644 --- a/test/unit/resolvers/customer/customer.test.js +++ b/test/unit/resolvers/customer/customer.test.js @@ -2,7 +2,6 @@ import { jest } from '@jest/globals' import { Permissions } from '../../../../app/data-sources/static/permissions.js' import { Customer, CustomerBusiness } from '../../../../app/graphql/resolvers/customer/customer.js' -import { Query } from '../../../../app/graphql/resolvers/customer/query.js' import { organisationPeopleByOrgId } from '../../../fixtures/organisation.js' import { buildPermissionsFromIdsAndLevels } from '../../../test-helpers/permissions.js' @@ -95,21 +94,6 @@ describe('Customer', () => { jest.clearAllMocks() }) - test('Query.customer.personId', async () => { - dataSources.mongoCustomer.findPersonIdByCRN.mockResolvedValue('internal person id') - const response = await Query.customer( - undefined, - { crn: personFixture.customerReferenceNumber }, - { dataSources } - ) - - expect(dataSources.mongoCustomer.findPersonIdByCRN).toHaveBeenCalledWith( - personFixture.customerReferenceNumber - ) - - expect(response).toEqual({ crn: 'crn-11111111', personId: 'internal person id' }) - }) - test('Customer.info', async () => { dataSources.ruralPaymentsCustomer.getPersonByPersonId.mockResolvedValue(personFixture) const response = await Customer.info({ personId: personFixture.id }, undefined, { diff --git a/test/unit/resolvers/customer/query.test.js b/test/unit/resolvers/customer/query.test.js new file mode 100644 index 00000000..443d0fcb --- /dev/null +++ b/test/unit/resolvers/customer/query.test.js @@ -0,0 +1,60 @@ +import { jest } from '@jest/globals' + +import { Query } from '../../../../app/graphql/resolvers/customer/query.js' + +const dataSources = { + ruralPaymentsCustomer: { + customerEmailExistsByEmailAddress: jest.fn() + }, + mongoCustomer: { + findPersonIdByCRN: jest.fn() + } +} + +describe('Query', () => { + beforeEach(() => { + jest.clearAllMocks() + }) + + describe('CustomerEmail', () => { + test('returns mail address and sets address in use to true when email is in use', async () => { + dataSources.ruralPaymentsCustomer.customerEmailExistsByEmailAddress.mockResolvedValue({ + emailDuplicated: true + }) + + const response = await Query.customerEmail( + undefined, + { emailAddress: 'test@example.com' }, + { + dataSources + } + ) + + expect( + dataSources.ruralPaymentsCustomer.customerEmailExistsByEmailAddress + ).toHaveBeenCalledWith('test@example.com') + expect(response).toMatchObject({ + emailAddress: 'test@example.com', + addressInUse: true + }) + }) + + test('returns mail address and sets address in use to false when email is not already in use', async () => { + dataSources.ruralPaymentsCustomer.customerEmailExistsByEmailAddress.mockResolvedValue({ + emailDuplicated: false + }) + + const response = await Query.customerEmail( + undefined, + { emailAddress: 'test@example.com' }, + { + dataSources + } + ) + expect(response).toMatchObject({ + emailAddress: 'test@example.com', + addressInUse: false + }) + }) + }) +})