UNPKG

@defra-fish/sales-api-service

Version:

Rod Licensing Sales API

280 lines (242 loc) • 10.9 kB
import { createPoclValidationError, updatePoclValidationError, getPoclValidationErrors } from '../pocl-validation-errors.service.js' import { persist, findById, PoclValidationError, executeQuery, findPoclValidationErrors } from '@defra-fish/dynamics-lib' import { getGlobalOptionSetValue } from '../../reference-data.service.js' import Boom from '@hapi/boom' jest.mock('@defra-fish/dynamics-lib', () => ({ ...jest.requireActual('@defra-fish/dynamics-lib'), findById: jest.fn(), persist: jest.fn(), executeQuery: jest.fn(), findPoclValidationErrors: jest.fn() })) const getPayload = () => ({ id: 'test-id', createTransactionPayload: { dataSource: 'DDE File', serialNumber: '14345-48457J', permissions: [ { licensee: { firstName: 'Daniel', lastName: 'Ricciardo', organisation: 'Fishy Endeavours', premises: '14 Howecroft Court', street: 'Eastmead Lane', town: 'Bristol', postcode: 'BS9 1HJ', country: 'GB-ENG', birthDate: '1989-07-01', email: 'daniel-ricc@example.com', mobilePhone: '07722 123456', preferredMethodOfNewsletter: 'Prefer not to be contacted', preferredMethodOfConfirmation: 'Email', preferredMethodOfReminder: 'Text', postalFulfilment: true }, permitId: 'test-permit-id', startDate: '2021-06-15', concessions: [{ type: 'Blue Badge', referenceNumber: '123456789' }] } ] }, finaliseTransactionPayload: { transactionFile: 'test-pocl-file.xml', payment: { timestamp: '2020-01-01T14:00:00Z', amount: 30, source: 'Direct Debit', channelId: '948594', method: 'Cash' } }, createTransactionError: { statusCode: 422, error: 'Data validation error', message: 'Error' } }) const getValidationError = payload => ({ ...payload.createTransactionPayload.permissions[0].licensee, serialNumber: payload.createTransactionPayload.serialNumber, dataSource: payload.createTransactionPayload.serialNumber.dataSource, transactionDate: payload.createTransactionPayload.permissions[0].issueDate, permitId: payload.createTransactionPayload.permissions[0].permitId, startDateUnvalidated: payload.createTransactionPayload.permissions[0].startDate, startDate: payload.createTransactionPayload.permissions[0].newStartDate, concessions: JSON.stringify(payload.createTransactionPayload.permissions[0].concessions), timestamp: payload.finaliseTransactionPayload.payment.timestamp, amount: payload.finaliseTransactionPayload.payment.amount, channelId: payload.finaliseTransactionPayload.payment.channelId, paymentSource: payload.finaliseTransactionPayload.payment.newPaymentSource, paymentSourceUnvalidated: payload.finaliseTransactionPayload.payment.source, methodOfPayment: payload.finaliseTransactionPayload.payment.method, status: 'Ready for Processing', errorMessage: payload.errorMessage }) jest.mock('../../reference-data.service.js', () => ({ getGlobalOptionSetValue: async (name, lookup) => { const optionSets = { defra_poclvalidationerrorstatus: [ { id: 1000, label: 'needs_review', description: 'Needs Review' }, { id: 1001, label: 'processed', description: 'Processed' }, { id: 1002, label: 'ready_for_processing', description: 'Ready for Processing' } ], defra_paymenttype: [{ id: 1010, label: 'cash', description: 'Cash' }], defra_datasource: [{ id: 1020, label: 'dde_file', description: 'DDE File' }], defra_preferredcontactmethod: [ { id: 1030, label: 'e-mail', description: 'Email' }, { id: 1031, label: 'prefer_no_contact', description: 'Prefer not to be contacted' }, { id: 1032, label: 'sms', description: 'Text' } ], defra_financialtransactionsource: [{ id: 1040, label: 'direct_debit', description: 'Direct Debit' }], defra_country: [{ id: 1050, label: 'uk_eng', description: 'GB-ENG' }] } const optionSet = optionSets[name].find(os => os.description === lookup) if (optionSet) { return optionSet } } })) describe('POCL validation error service', () => { beforeAll(() => { findById.mockImplementation(() => getValidationError(getPayload())) }) beforeEach(jest.clearAllMocks) describe('createPoclValidationError', () => { const getPayloadWithoutTransactionFile = () => { const payload = getPayload() delete payload.finaliseTransactionPayload.transactionFile return payload } it('maps the record to an instance of PoclValidationError', async () => { await createPoclValidationError(getPayloadWithoutTransactionFile(), 'test-pocl-file.xml') const [[[poclValidationError]]] = persist.mock.calls expect(poclValidationError).toBeInstanceOf(PoclValidationError) }) it('creates the validation record', async () => { await createPoclValidationError(getPayloadWithoutTransactionFile(), 'test-pocl-file.xml') const [[[poclValidationError]]] = persist.mock.calls expect(poclValidationError).toMatchSnapshot() }) }) describe('updatePoclValidationError', () => { const getPayloadWithoutCreateTransactionError = () => { const payload = getPayload() delete payload.createTransactionError payload.errorMessage = 'Invalid email address' return payload } describe('when validation error record exists', () => { it('retrieves existing record', async () => { const payload = getPayloadWithoutCreateTransactionError() await updatePoclValidationError('pocl-validation-error-id', payload) expect(findById).toBeCalledWith(PoclValidationError, 'pocl-validation-error-id') }) it('maps a country not in optionset to countryUnvalidated', async () => { const payload = getPayload() payload.createTransactionPayload.permissions[0].licensee.country = 'WAK' await updatePoclValidationError('abc-123-def-456', payload) const [[[poclValidationError]]] = persist.mock.calls expect(poclValidationError.countryUnvalidated).toBe('WAK') }) it('maps an invalid date to startDateUnvalidated', async () => { const payload = getPayload() payload.createTransactionPayload.permissions[0].startDate = '15/6/2021' await updatePoclValidationError('abc-123-def-456', payload) const [[[poclValidationError]]] = persist.mock.calls expect(poclValidationError.startDateUnvalidated).toBe('15/6/2021') }) describe('and status is not provided', () => { it('sets the status to "Needs Review"', async () => { const validationErrorNeedsReview = await getGlobalOptionSetValue('defra_poclvalidationerrorstatus', 'Needs Review') const payload = getPayloadWithoutCreateTransactionError() await updatePoclValidationError('pocl-validation-error-id', payload) const [[[poclValidationError]]] = persist.mock.calls expect(poclValidationError.status.label).toBe(validationErrorNeedsReview.label) }) it('the state code is not set', async () => { const payload = getPayloadWithoutCreateTransactionError() await updatePoclValidationError('pocl-validation-error-id', payload) const [[[poclValidationError]]] = persist.mock.calls expect(poclValidationError.stateCode).toBe(undefined) }) it('updates the validation record', async () => { const payload = getPayloadWithoutCreateTransactionError() await updatePoclValidationError('pocl-validation-error-id', payload) const [[[poclValidationError]]] = persist.mock.calls expect(poclValidationError).toMatchSnapshot() }) }) describe('and status is processed', () => { const getProcessedPayload = () => { const payload = getPayloadWithoutCreateTransactionError() payload.status = 'Processed' return payload } const updateAndRetrieveError = async () => { const payload = getProcessedPayload() await updatePoclValidationError('pocl-validation-error-id', payload) const [[[poclValidationError]]] = persist.mock.calls return poclValidationError } it('the status is set to processed', async () => { const validationErrorProcessed = await getGlobalOptionSetValue('defra_poclvalidationerrorstatus', 'Processed') const poclValidationError = await updateAndRetrieveError() expect(poclValidationError.status.label).toBe(validationErrorProcessed.label) }) it('the state code is set to 1', async () => { const poclValidationError = await updateAndRetrieveError() expect(poclValidationError.stateCode).toBe(1) }) it('updates the validation record', async () => { const poclValidationError = await updateAndRetrieveError() expect(poclValidationError).toMatchSnapshot() }) }) }) describe('when the validation error record does not exist', () => { beforeEach(async () => { findById.mockResolvedValueOnce(null) }) it('throws a 404 error', async () => { await expect(updatePoclValidationError('pocl-validation-error-id', getPayloadWithoutCreateTransactionError())).rejects.toEqual( Boom.notFound('A POCL validation error with the given identifier could not be found') ) }) it('does not call persist to update record', async () => { try { await updatePoclValidationError('pocl-validation-error-id', getPayloadWithoutCreateTransactionError()) } catch (err) {} expect(persist).not.toBeCalled() }) }) }) describe('getPoclValidationErrors', () => { beforeAll(async () => { findPoclValidationErrors.mockReturnValue({ foo: 'bar' }) executeQuery.mockResolvedValue([ { fields: { some: 'fields' }, entity: { test: 'result' } }, { fields: { some: 'more fields' }, entity: { another: 'result' } } ]) }) it('passes the "Ready for Processing" status to the findPoclValidationErrors query', async () => { const status = await getGlobalOptionSetValue(PoclValidationError.definition.mappings.status.ref, 'Ready for Processing') await getPoclValidationErrors() expect(findPoclValidationErrors).toHaveBeenCalledWith(status) }) it('executes the output of the Pocl query', async () => { await getPoclValidationErrors() expect(executeQuery).toHaveBeenCalledWith({ foo: 'bar' }) }) it('returns the entities retrieved from Dynamics', async () => { const result = await getPoclValidationErrors() expect(result).toMatchSnapshot() }) }) })