@defra-fish/sales-api-service 1.58.0 → 1.59.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@defra-fish/sales-api-service",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.59.0-rc.0",
|
|
4
4
|
"description": "Rod Licensing Sales API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"test": "echo \"Error: run tests from root\" && exit 1"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@defra-fish/business-rules-lib": "1.
|
|
39
|
-
"@defra-fish/connectors-lib": "1.
|
|
40
|
-
"@defra-fish/dynamics-lib": "1.
|
|
38
|
+
"@defra-fish/business-rules-lib": "1.59.0-rc.0",
|
|
39
|
+
"@defra-fish/connectors-lib": "1.59.0-rc.0",
|
|
40
|
+
"@defra-fish/dynamics-lib": "1.59.0-rc.0",
|
|
41
41
|
"@hapi/boom": "^9.1.2",
|
|
42
42
|
"@hapi/hapi": "^20.1.3",
|
|
43
43
|
"@hapi/inert": "^6.0.3",
|
|
@@ -52,5 +52,5 @@
|
|
|
52
52
|
"moment-timezone": "^0.5.34",
|
|
53
53
|
"uuid": "^8.3.2"
|
|
54
54
|
},
|
|
55
|
-
"gitHead": "
|
|
55
|
+
"gitHead": "01bc1d91c4f25234b008dafe06b0525760f9c752"
|
|
56
56
|
}
|
|
@@ -5,11 +5,10 @@ import { permitSchema } from './permit.schema.js'
|
|
|
5
5
|
import { contactResponseSchema } from './contact.schema.js'
|
|
6
6
|
import { finalisedPermissionSchemaContent } from './permission.schema.js'
|
|
7
7
|
|
|
8
|
+
const REFERENCE_LENGTH = 6
|
|
9
|
+
|
|
8
10
|
export const authenticateRenewalRequestParamsSchema = Joi.object({
|
|
9
|
-
referenceNumber: Joi.string()
|
|
10
|
-
.min(6)
|
|
11
|
-
.required()
|
|
12
|
-
.description('The permission reference number (supports partial)')
|
|
11
|
+
referenceNumber: Joi.string().min(REFERENCE_LENGTH).required().description('The permission reference number (supports partial)')
|
|
13
12
|
}).label('authenticate-renewal-request-params')
|
|
14
13
|
|
|
15
14
|
export const authenticateRenewalRequestQuerySchema = Joi.object({
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { contactForLicenseeNoReference, executeQuery } from '@defra-fish/dynamics-lib'
|
|
2
2
|
import db from 'debug'
|
|
3
3
|
jest.mock('@defra-fish/dynamics-lib')
|
|
4
4
|
jest.mock('debug')
|
|
@@ -10,7 +10,7 @@ describe('executeWithErrorLog', () => {
|
|
|
10
10
|
executeQuery.mockImplementation(() => {
|
|
11
11
|
throw new Error()
|
|
12
12
|
})
|
|
13
|
-
|
|
13
|
+
contactForLicenseeNoReference.mockReturnValueOnce({ filter: 'query filter test' })
|
|
14
14
|
const authenticate = require('../authenticate.js').default
|
|
15
15
|
const [
|
|
16
16
|
{
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import initialiseServer from '../../server.js'
|
|
2
|
-
import { executeQuery,
|
|
2
|
+
import { contactForLicenseeNoReference, executeQuery, permissionForContacts } from '@defra-fish/dynamics-lib'
|
|
3
3
|
import {
|
|
4
4
|
MOCK_EXISTING_PERMISSION_ENTITY,
|
|
5
5
|
MOCK_EXISTING_CONTACT_ENTITY,
|
|
@@ -10,8 +10,9 @@ import {
|
|
|
10
10
|
|
|
11
11
|
jest.mock('@defra-fish/dynamics-lib', () => ({
|
|
12
12
|
...jest.requireActual('@defra-fish/dynamics-lib'),
|
|
13
|
-
|
|
14
|
-
executeQuery: jest.fn()
|
|
13
|
+
contactForLicenseeNoReference: jest.fn(),
|
|
14
|
+
executeQuery: jest.fn(),
|
|
15
|
+
permissionForContacts: jest.fn()
|
|
15
16
|
}))
|
|
16
17
|
|
|
17
18
|
let server = null
|
|
@@ -27,6 +28,12 @@ describe('authenticate handler', () => {
|
|
|
27
28
|
|
|
28
29
|
describe('authenticateRenewal', () => {
|
|
29
30
|
it('authenticates a renewal request', async () => {
|
|
31
|
+
executeQuery.mockResolvedValueOnce([
|
|
32
|
+
{
|
|
33
|
+
entity: MOCK_EXISTING_CONTACT_ENTITY,
|
|
34
|
+
expanded: {}
|
|
35
|
+
}
|
|
36
|
+
])
|
|
30
37
|
executeQuery.mockResolvedValueOnce([
|
|
31
38
|
{
|
|
32
39
|
entity: MOCK_EXISTING_PERMISSION_ENTITY,
|
|
@@ -42,7 +49,6 @@ describe('authenticate handler', () => {
|
|
|
42
49
|
method: 'GET',
|
|
43
50
|
url: '/authenticate/renewal/CD379B?licenseeBirthDate=2000-01-01&licenseePostcode=AB12 3CD'
|
|
44
51
|
})
|
|
45
|
-
expect(permissionForLicensee).toHaveBeenCalledWith('CD379B', '2000-01-01', 'AB12 3CD')
|
|
46
52
|
expect(result.statusCode).toBe(200)
|
|
47
53
|
expect(JSON.parse(result.payload)).toMatchObject({
|
|
48
54
|
permission: expect.objectContaining({
|
|
@@ -61,6 +67,12 @@ describe('authenticate handler', () => {
|
|
|
61
67
|
|
|
62
68
|
describe('if no concessions are returned', () => {
|
|
63
69
|
beforeEach(() => {
|
|
70
|
+
executeQuery.mockResolvedValueOnce([
|
|
71
|
+
{
|
|
72
|
+
entity: MOCK_EXISTING_CONTACT_ENTITY,
|
|
73
|
+
expanded: {}
|
|
74
|
+
}
|
|
75
|
+
])
|
|
64
76
|
executeQuery.mockResolvedValueOnce([
|
|
65
77
|
{
|
|
66
78
|
entity: MOCK_EXISTING_PERMISSION_ENTITY,
|
|
@@ -73,12 +85,20 @@ describe('authenticate handler', () => {
|
|
|
73
85
|
])
|
|
74
86
|
})
|
|
75
87
|
|
|
76
|
-
it('should call
|
|
88
|
+
it('should call contactForLicenseeNoReference with dob and postcode for a renewal request', async () => {
|
|
89
|
+
await server.inject({
|
|
90
|
+
method: 'GET',
|
|
91
|
+
url: '/authenticate/renewal/CD379B?licenseeBirthDate=2000-01-01&licenseePostcode=AB12 3CD'
|
|
92
|
+
})
|
|
93
|
+
expect(contactForLicenseeNoReference).toHaveBeenCalledWith('2000-01-01', 'AB12 3CD')
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it('should call permissionForContacts with contact ids from contactForLicenseeNoReference', async () => {
|
|
77
97
|
await server.inject({
|
|
78
98
|
method: 'GET',
|
|
79
99
|
url: '/authenticate/renewal/CD379B?licenseeBirthDate=2000-01-01&licenseePostcode=AB12 3CD'
|
|
80
100
|
})
|
|
81
|
-
expect(
|
|
101
|
+
expect(permissionForContacts).toHaveBeenCalledWith([MOCK_EXISTING_CONTACT_ENTITY.id])
|
|
82
102
|
})
|
|
83
103
|
|
|
84
104
|
it('returns 200 from a renewal request', async () => {
|
|
@@ -105,7 +125,13 @@ describe('authenticate handler', () => {
|
|
|
105
125
|
})
|
|
106
126
|
|
|
107
127
|
it('throws 500 errors if more than one result was found for the query', async () => {
|
|
108
|
-
executeQuery.mockResolvedValueOnce([
|
|
128
|
+
executeQuery.mockResolvedValueOnce([
|
|
129
|
+
{
|
|
130
|
+
entity: MOCK_EXISTING_CONTACT_ENTITY,
|
|
131
|
+
expanded: {}
|
|
132
|
+
}
|
|
133
|
+
])
|
|
134
|
+
executeQuery.mockResolvedValueOnce([{ entity: { referenceNumber: 'CD379B' } }, { entity: { referenceNumber: 'CD379B' } }])
|
|
109
135
|
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(jest.fn())
|
|
110
136
|
const result = await server.inject({
|
|
111
137
|
method: 'GET',
|
|
@@ -121,6 +147,26 @@ describe('authenticate handler', () => {
|
|
|
121
147
|
})
|
|
122
148
|
|
|
123
149
|
it('throws 401 errors if the renewal could not be authenticated', async () => {
|
|
150
|
+
executeQuery.mockResolvedValueOnce([
|
|
151
|
+
{
|
|
152
|
+
entity: MOCK_EXISTING_CONTACT_ENTITY,
|
|
153
|
+
expanded: {}
|
|
154
|
+
}
|
|
155
|
+
])
|
|
156
|
+
executeQuery.mockResolvedValueOnce([])
|
|
157
|
+
const result = await server.inject({
|
|
158
|
+
method: 'GET',
|
|
159
|
+
url: '/authenticate/renewal/CD379B?licenseeBirthDate=2000-01-01&licenseePostcode=AB12 3CD'
|
|
160
|
+
})
|
|
161
|
+
expect(result.statusCode).toBe(401)
|
|
162
|
+
expect(JSON.parse(result.payload)).toMatchObject({
|
|
163
|
+
error: 'Unauthorized',
|
|
164
|
+
message: 'The licensee could not be authenticated',
|
|
165
|
+
statusCode: 401
|
|
166
|
+
})
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
it('throws 401 errors if no contact to be authenticated', async () => {
|
|
124
170
|
executeQuery.mockResolvedValueOnce([])
|
|
125
171
|
const result = await server.inject({
|
|
126
172
|
method: 'GET',
|
|
@@ -5,8 +5,9 @@ import {
|
|
|
5
5
|
authenticateRenewalResponseSchema
|
|
6
6
|
} from '../../schema/authenticate.schema.js'
|
|
7
7
|
import db from 'debug'
|
|
8
|
-
import {
|
|
8
|
+
import { permissionForContacts, concessionsByIds, executeQuery, contactForLicenseeNoReference } from '@defra-fish/dynamics-lib'
|
|
9
9
|
const debug = db('sales:renewal-authentication')
|
|
10
|
+
const failAuthenticate = 'The licensee could not be authenticated'
|
|
10
11
|
|
|
11
12
|
const executeWithErrorLog = async query => {
|
|
12
13
|
try {
|
|
@@ -24,33 +25,37 @@ export default [
|
|
|
24
25
|
options: {
|
|
25
26
|
handler: async (request, h) => {
|
|
26
27
|
const { licenseeBirthDate, licenseePostcode } = request.query
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
28
|
+
const contacts = await executeWithErrorLog(contactForLicenseeNoReference(licenseeBirthDate, licenseePostcode))
|
|
29
|
+
if (contacts.length > 0) {
|
|
30
|
+
const contactIds = contacts.map(contact => contact.entity.id)
|
|
31
|
+
const permissions = await executeWithErrorLog(permissionForContacts(contactIds))
|
|
32
|
+
const results = permissions.filter(p => p.entity.referenceNumber.endsWith(request.params.referenceNumber))
|
|
33
|
+
if (results.length === 1) {
|
|
34
|
+
let concessionProofs = []
|
|
35
|
+
if (results[0].expanded.concessionProofs.length > 0) {
|
|
36
|
+
const ids = results[0].expanded.concessionProofs.map(f => f.entity.id)
|
|
37
|
+
concessionProofs = await executeWithErrorLog(concessionsByIds(ids))
|
|
38
|
+
}
|
|
39
|
+
return h
|
|
40
|
+
.response({
|
|
41
|
+
permission: {
|
|
42
|
+
...results[0].entity.toJSON(),
|
|
43
|
+
licensee: results[0].expanded.licensee.entity.toJSON(),
|
|
44
|
+
concessions: concessionProofs.map(c => ({
|
|
45
|
+
id: c.expanded.concession.entity.id,
|
|
46
|
+
proof: c.entity.toJSON()
|
|
47
|
+
})),
|
|
48
|
+
permit: results[0].expanded.permit.entity.toJSON()
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
.code(200)
|
|
52
|
+
} else if (results.length === 0) {
|
|
53
|
+
throw Boom.unauthorized(failAuthenticate)
|
|
54
|
+
} else {
|
|
55
|
+
throw new Error('Unable to authenticate, non-unique results for query')
|
|
36
56
|
}
|
|
37
|
-
return h
|
|
38
|
-
.response({
|
|
39
|
-
permission: {
|
|
40
|
-
...results[0].entity.toJSON(),
|
|
41
|
-
licensee: results[0].expanded.licensee.entity.toJSON(),
|
|
42
|
-
concessions: concessionProofs.map(c => ({
|
|
43
|
-
id: c.expanded.concession.entity.id,
|
|
44
|
-
proof: c.entity.toJSON()
|
|
45
|
-
})),
|
|
46
|
-
permit: results[0].expanded.permit.entity.toJSON()
|
|
47
|
-
}
|
|
48
|
-
})
|
|
49
|
-
.code(200)
|
|
50
|
-
} else if (results.length === 0) {
|
|
51
|
-
throw Boom.unauthorized('The licensee could not be authenticated')
|
|
52
57
|
} else {
|
|
53
|
-
throw
|
|
58
|
+
throw Boom.unauthorized(failAuthenticate)
|
|
54
59
|
}
|
|
55
60
|
},
|
|
56
61
|
description: 'Authenticate a licensee by checking the licence number corresponds with the provided contact details',
|
|
@@ -66,7 +71,7 @@ export default [
|
|
|
66
71
|
'hapi-swagger': {
|
|
67
72
|
responses: {
|
|
68
73
|
200: { description: 'The licensee was successfully authenticated', schema: authenticateRenewalResponseSchema },
|
|
69
|
-
401: { description:
|
|
74
|
+
401: { description: failAuthenticate }
|
|
70
75
|
},
|
|
71
76
|
order: 1
|
|
72
77
|
}
|