@defra-fish/gafl-webapp-service 1.65.0-rc.1 → 1.65.0-rc.10

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.
Files changed (30) hide show
  1. package/package.json +4 -4
  2. package/src/handlers/__tests__/cancel-recurring-payment-authentication-handler.spec.js +62 -45
  3. package/src/handlers/cancel-recurring-payment-authentication-handler.js +33 -25
  4. package/src/handlers/result-functions.js +5 -2
  5. package/src/locales/cy.json +33 -7
  6. package/src/locales/en.json +38 -0
  7. package/src/pages/journey-goal/__tests__/result-function.spec.js +33 -0
  8. package/src/pages/journey-goal/__tests__/route.spec.js +50 -0
  9. package/src/pages/journey-goal/journey-goal.njk +52 -0
  10. package/src/pages/journey-goal/result-function.js +21 -0
  11. package/src/pages/journey-goal/route.js +10 -0
  12. package/src/pages/recurring-payments/cancel/agreement-not-found/__tests__/route.spec.js +129 -0
  13. package/src/pages/recurring-payments/cancel/agreement-not-found/cancel-rp-agreement-not-found.njk +15 -0
  14. package/src/pages/recurring-payments/cancel/agreement-not-found/route.js +23 -0
  15. package/src/pages/recurring-payments/cancel/already-cancelled/__tests__/route.spec.js +115 -0
  16. package/src/pages/recurring-payments/cancel/already-cancelled/already-cancelled.njk +28 -0
  17. package/src/pages/recurring-payments/cancel/already-cancelled/route.js +25 -0
  18. package/src/pages/recurring-payments/cancel/confirm/__tests__/route.spec.js +11 -1
  19. package/src/pages/recurring-payments/cancel/confirm/cancel-rp-confirm.njk +12 -10
  20. package/src/pages/recurring-payments/cancel/confirm/route.js +3 -3
  21. package/src/pages/recurring-payments/cancel/details/__tests__/route.spec.js +70 -8
  22. package/src/pages/recurring-payments/cancel/details/route.js +12 -4
  23. package/src/pages/recurring-payments/cancel/licence-not-found/__tests__/route.spec.js +21 -0
  24. package/src/pages/recurring-payments/cancel/licence-not-found/licence-not-found.njk +27 -0
  25. package/src/pages/recurring-payments/cancel/licence-not-found/route.js +4 -0
  26. package/src/routes/__tests__/__snapshots__/telesales-routes.spec.js.snap +96 -0
  27. package/src/routes/__tests__/back-links.spec.js +67 -2
  28. package/src/routes/journey-definition.js +75 -11
  29. package/src/routes/telesales-routes.js +15 -5
  30. package/src/uri.js +11 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defra-fish/gafl-webapp-service",
3
- "version": "1.65.0-rc.1",
3
+ "version": "1.65.0-rc.10",
4
4
  "description": "The websales frontend for the GAFL service",
5
5
  "type": "module",
6
6
  "engines": {
@@ -36,8 +36,8 @@
36
36
  "prepare": "gulp --gulpfile build/gulpfile.cjs"
37
37
  },
38
38
  "dependencies": {
39
- "@defra-fish/business-rules-lib": "1.65.0-rc.1",
40
- "@defra-fish/connectors-lib": "1.65.0-rc.1",
39
+ "@defra-fish/business-rules-lib": "1.65.0-rc.10",
40
+ "@defra-fish/connectors-lib": "1.65.0-rc.10",
41
41
  "@defra/hapi-gapi": "2.0.0",
42
42
  "@hapi/boom": "9.1.2",
43
43
  "@hapi/catbox-redis": "6.0.2",
@@ -79,5 +79,5 @@
79
79
  "./gafl-jest-matchers.js"
80
80
  ]
81
81
  },
82
- "gitHead": "3e4014cd3d4fae6d6dc6b7f5b338821a572286fb"
82
+ "gitHead": "a0c3f3c346d5fa6bf8559fa198b3c6db68f4bc99"
83
83
  }
@@ -1,6 +1,11 @@
1
1
  import handler from '../cancel-recurring-payment-authentication-handler'
2
- import { CANCEL_RP_IDENTIFY, CANCEL_RP_DETAILS } from '../../uri.js'
3
- import { addLanguageCodeToUri } from '../../processors/uri-helper.js'
2
+ import {
3
+ CANCEL_RP_IDENTIFY,
4
+ CANCEL_RP_DETAILS,
5
+ CANCEL_RP_AGREEMENT_NOT_FOUND,
6
+ CANCEL_RP_ALREADY_CANCELLED,
7
+ CANCEL_RP_LICENCE_NOT_FOUND
8
+ } from '../../uri.js'
4
9
  import { salesApi } from '@defra-fish/connectors-lib'
5
10
 
6
11
  jest.mock('../../processors/uri-helper.js')
@@ -19,7 +24,10 @@ jest.mock('@defra-fish/business-rules-lib', () => ({
19
24
  }))
20
25
  jest.mock('../../uri.js', () => ({
21
26
  CANCEL_RP_IDENTIFY: { page: 'cancel-rp-identify page', uri: Symbol('cancel-rp-identify-uri') },
22
- CANCEL_RP_DETAILS: { uri: Symbol('cancel-rp-details-uri') }
27
+ CANCEL_RP_DETAILS: { uri: Symbol('cancel-rp-details-uri') },
28
+ CANCEL_RP_AGREEMENT_NOT_FOUND: { uri: Symbol('cancel-rp-agreement-not-found-uri') },
29
+ CANCEL_RP_ALREADY_CANCELLED: { uri: Symbol('cancel-rp-already-cancelled-uri ') },
30
+ CANCEL_RP_LICENCE_NOT_FOUND: { uri: Symbol('cancel-rp-licence-not-found-uri') }
23
31
  }))
24
32
  jest.mock('../../processors/recurring-payments-write-cache.js')
25
33
 
@@ -52,22 +60,15 @@ const getSampleRequest = (payloadOverride = {}) => {
52
60
  }
53
61
  }
54
62
 
55
- const getSampleResponseTooklkit = () => ({
56
- redirectWithLanguageCode: jest.fn().mockReturnValue('redirected')
63
+ const getSampleResponseToolkit = () => ({
64
+ redirectWithLanguageCode: jest.fn(() => 'redirected')
57
65
  })
58
66
 
59
- const invokeHandlerWithMocks = async ({ salesApiResponse, decoratedIdentifyUri } = {}) => {
60
- if (typeof salesApiResponse !== 'undefined') {
67
+ const invokeHandlerWithMocks = async ({ h = getSampleResponseToolkit(), salesApiResponse } = {}) => {
68
+ if (salesApiResponse) {
61
69
  salesApi.authenticateRecurringPayment.mockResolvedValueOnce(salesApiResponse)
62
70
  }
63
- if (decoratedIdentifyUri) {
64
- addLanguageCodeToUri.mockReturnValueOnce(decoratedIdentifyUri)
65
- }
66
71
  const request = getSampleRequest()
67
- const h = getSampleResponseTooklkit()
68
- if (decoratedIdentifyUri) {
69
- h.redirect = jest.fn().mockReturnValue('redirect-response')
70
- }
71
72
  const result = await handler(request, h)
72
73
  return { request, h, result }
73
74
  }
@@ -106,24 +107,35 @@ describe('Cancel RP Authentication Handler', () => {
106
107
  })
107
108
 
108
109
  describe('Unsuccessful authentication - no match', () => {
109
- it('redirects to the decorated identify URI', async () => {
110
- const { h } = await invokeHandlerWithMocks({ salesApiResponse: null, decoratedIdentifyUri: 'decorated-identify-uri' })
111
- expect(h.redirect).toHaveBeenCalledWith('decorated-identify-uri')
110
+ it('redirects to the CANCEL_RP_LICENCE_NOT_FOUND.uri', async () => {
111
+ const { h } = await invokeHandlerWithMocks({ salesApiResponse: null })
112
+ expect(h.redirectWithLanguageCode).toHaveBeenCalledWith(CANCEL_RP_LICENCE_NOT_FOUND.uri)
113
+ })
114
+
115
+ it('returns value of redirect', async () => {
116
+ const h = getSampleResponseToolkit()
117
+ const redirectResult = Symbol('redirected')
118
+ h.redirectWithLanguageCode.mockReturnValueOnce(redirectResult)
119
+ const { result } = await invokeHandlerWithMocks({
120
+ h,
121
+ salesApiResponse: null
122
+ })
123
+ expect(result).toBe(redirectResult)
112
124
  })
113
125
 
114
126
  it('sets page cache error and preserves payload', async () => {
115
- const { request } = await invokeHandlerWithMocks({ salesApiResponse: null, decoratedIdentifyUri: 'decorated-identify-uri' })
127
+ const { request } = await invokeHandlerWithMocks({ salesApiResponse: null })
116
128
  expect(request.cache().helpers.page.setCurrentPermission).toHaveBeenCalledWith(
117
129
  CANCEL_RP_IDENTIFY.page,
118
130
  expect.objectContaining({
119
131
  payload: expect.any(Object),
120
- error: { referenceNumber: 'not-found' }
132
+ errorRedirect: true
121
133
  })
122
134
  )
123
135
  })
124
136
 
125
137
  it('marks status as unauthorised', async () => {
126
- const { request } = await invokeHandlerWithMocks({ salesApiResponse: null, decoratedIdentifyUri: 'decorated-identify-uri' })
138
+ const { request } = await invokeHandlerWithMocks({ salesApiResponse: null })
127
139
  expect(request.cache().helpers.status.setCurrentPermission).toHaveBeenCalledWith(
128
140
  expect.objectContaining({ authentication: { authorised: false } })
129
141
  )
@@ -131,26 +143,23 @@ describe('Cancel RP Authentication Handler', () => {
131
143
  })
132
144
 
133
145
  describe('Unsuccessful authentication - no recurring payment agreement', () => {
134
- it('redirects to the decorated identify URI', async () => {
146
+ it('redirects to the CANCEL_RP_AGREEMENT_NOT_FOUND.uri', async () => {
135
147
  const { h } = await invokeHandlerWithMocks({
136
148
  salesApiResponse: { permission: { id: 'perm-id' }, recurringPayment: null },
137
149
  decoratedIdentifyUri: 'decorated-identify-uri'
138
150
  })
139
- expect(h.redirect).toHaveBeenCalledWith('decorated-identify-uri')
151
+ expect(h.redirectWithLanguageCode).toHaveBeenCalledWith(CANCEL_RP_AGREEMENT_NOT_FOUND.uri)
140
152
  })
141
153
 
142
- it('sets page cache error for no RCP setup', async () => {
143
- const { request } = await invokeHandlerWithMocks({
144
- salesApiResponse: { permission: { id: 'perm-id' }, recurringPayment: null },
145
- decoratedIdentifyUri: 'decorated-identify-uri'
154
+ it('returns value of redirect', async () => {
155
+ const h = getSampleResponseToolkit()
156
+ const redirectResult = Symbol('redirected')
157
+ h.redirectWithLanguageCode.mockReturnValueOnce(redirectResult)
158
+ const { result } = await invokeHandlerWithMocks({
159
+ h,
160
+ salesApiResponse: { permission: { id: 'perm-id' }, recurringPayment: null }
146
161
  })
147
- expect(request.cache().helpers.page.setCurrentPermission).toHaveBeenCalledWith(
148
- CANCEL_RP_IDENTIFY.page,
149
- expect.objectContaining({
150
- payload: expect.any(Object),
151
- error: { recurringPayment: 'not-set-up' }
152
- })
153
- )
162
+ expect(result).toBe(redirectResult)
154
163
  })
155
164
 
156
165
  it('marks status as unauthorised', async () => {
@@ -164,33 +173,41 @@ describe('Cancel RP Authentication Handler', () => {
164
173
  })
165
174
  })
166
175
 
167
- describe('Unsuccessful authentication - RCP cancelled', () => {
168
- it('redirects to the decorated identify URI', async () => {
176
+ describe('Unsuccessful authentication - RCP already cancelled', () => {
177
+ it('redirects to the CANCEL_RP_ALREADY_CANCELLED.uri', async () => {
169
178
  const { h } = await invokeHandlerWithMocks({
170
- salesApiResponse: { permission: { id: 'perm-id' }, recurringPayment: { id: 'rcp-id', status: 1, cancelledDate: '2024-01-01' } },
171
- decoratedIdentifyUri: 'decorated-identify-uri'
179
+ salesApiResponse: { permission: { id: 'perm-id' }, recurringPayment: { id: 'rcp-id', status: 1, cancelledDate: '2024-01-01' } }
172
180
  })
173
- expect(h.redirect).toHaveBeenCalledWith('decorated-identify-uri')
181
+ expect(h.redirectWithLanguageCode).toHaveBeenCalledWith(CANCEL_RP_ALREADY_CANCELLED.uri)
174
182
  })
175
183
 
176
- it('sets page cache error for RCP cancelled', async () => {
184
+ it('returns value of redirect', async () => {
185
+ const h = getSampleResponseToolkit()
186
+ const redirectResult = Symbol('redirected')
187
+ h.redirectWithLanguageCode.mockReturnValueOnce(redirectResult)
188
+ const { result } = await invokeHandlerWithMocks({
189
+ h,
190
+ salesApiResponse: { permission: { id: 'perm-id' }, recurringPayment: { id: 'rcp-id', status: 1, cancelledDate: '2024-01-01' } }
191
+ })
192
+ expect(result).toBe(redirectResult)
193
+ })
194
+
195
+ it('sets page cache for RCP already cancelled', async () => {
177
196
  const { request } = await invokeHandlerWithMocks({
178
- salesApiResponse: { permission: { id: 'perm-id' }, recurringPayment: { id: 'rcp-id', status: 1, cancelledDate: '2024-01-01' } },
179
- decoratedIdentifyUri: 'decorated-identify-uri'
197
+ salesApiResponse: { permission: { id: 'perm-id' }, recurringPayment: { id: 'rcp-id', status: 1, cancelledDate: '2024-01-01' } }
180
198
  })
181
199
  expect(request.cache().helpers.page.setCurrentPermission).toHaveBeenCalledWith(
182
200
  CANCEL_RP_IDENTIFY.page,
183
201
  expect.objectContaining({
184
202
  payload: expect.any(Object),
185
- error: { recurringPayment: 'rcp-cancelled' }
203
+ errorRedirect: true
186
204
  })
187
205
  )
188
206
  })
189
207
 
190
208
  it('marks status as unauthorised', async () => {
191
209
  const { request } = await invokeHandlerWithMocks({
192
- salesApiResponse: { permission: { id: 'perm-id' }, recurringPayment: { id: 'rcp-id', status: 1, cancelledDate: '2024-01-01' } },
193
- decoratedIdentifyUri: 'decorated-identify-uri'
210
+ salesApiResponse: { permission: { id: 'perm-id' }, recurringPayment: { id: 'rcp-id', status: 1, cancelledDate: '2024-01-01' } }
194
211
  })
195
212
  expect(request.cache().helpers.status.setCurrentPermission).toHaveBeenCalledWith(
196
213
  expect.objectContaining({ authentication: { authorised: false } })
@@ -207,7 +224,7 @@ describe('Cancel RP Authentication Handler', () => {
207
224
  request.cache().helpers.status.getCurrentPermission.mockReturnValueOnce({
208
225
  referenceNumber: 'A1B2C3'
209
226
  })
210
- const h = getSampleResponseTooklkit()
227
+ const h = getSampleResponseToolkit()
211
228
  await handler(request, h)
212
229
  expect(salesApi.authenticateRecurringPayment).toHaveBeenCalledWith('A1B2C3', expect.anything(), expect.anything())
213
230
  })
@@ -1,26 +1,21 @@
1
- import { CANCEL_RP_IDENTIFY, CANCEL_RP_DETAILS } from '../../src/uri.js'
2
- import { addLanguageCodeToUri } from '../processors/uri-helper.js'
1
+ import {
2
+ CANCEL_RP_IDENTIFY,
3
+ CANCEL_RP_DETAILS,
4
+ CANCEL_RP_AGREEMENT_NOT_FOUND,
5
+ CANCEL_RP_ALREADY_CANCELLED,
6
+ CANCEL_RP_LICENCE_NOT_FOUND
7
+ } from '../../src/uri.js'
3
8
  import { salesApi } from '@defra-fish/connectors-lib'
4
9
  import { validation } from '@defra-fish/business-rules-lib'
5
10
  import { setupCancelRecurringPaymentCacheFromAuthResult } from '../processors/recurring-payments-write-cache.js'
11
+ import { cacheDateFormat } from '../../src/processors/date-and-time-display.js'
12
+ import moment from 'moment-timezone'
6
13
  import Joi from 'joi'
7
14
 
8
- const buildAuthFailure = (referenceNumber, payload, error) => ({
9
- page: {
10
- page: CANCEL_RP_IDENTIFY.page,
11
- data: { payload, error }
12
- },
13
- status: {
14
- referenceNumber,
15
- authentication: { authorised: false }
16
- },
17
- redirectPath: CANCEL_RP_IDENTIFY.uri
18
- })
19
-
20
- const applyAuthFailure = async (request, h, failure) => {
21
- await request.cache().helpers.page.setCurrentPermission(failure.page.page, failure.page.data)
22
- await request.cache().helpers.status.setCurrentPermission(failure.status)
23
- return h.redirect(addLanguageCodeToUri(request, failure.redirectPath))
15
+ const applyAuthFailure = async (request, h, { pageData, redirectUri, statusData }) => {
16
+ await request.cache().helpers.page.setCurrentPermission(CANCEL_RP_IDENTIFY.page, pageData)
17
+ await request.cache().helpers.status.setCurrentPermission(statusData)
18
+ return h.redirectWithLanguageCode(redirectUri)
24
19
  }
25
20
 
26
21
  const cancelRecurringPaymentAuthenticationHandler = async (request, h) => {
@@ -36,16 +31,29 @@ const cancelRecurringPaymentAuthenticationHandler = async (request, h) => {
36
31
 
37
32
  const authenticationResult = await salesApi.authenticateRecurringPayment(referenceNumber, dateOfBirth, postcode)
38
33
 
39
- const failures = error => applyAuthFailure(request, h, buildAuthFailure(referenceNumber, payload, error))
34
+ const context = {
35
+ pageData: { payload },
36
+ statusData: { referenceNumber, authentication: { authorised: false } },
37
+ redirectUri: CANCEL_RP_IDENTIFY.uri
38
+ }
40
39
 
41
40
  if (!authenticationResult) {
42
- return failures({ referenceNumber: 'not-found' })
43
- }
44
- if (!authenticationResult.recurringPayment) {
45
- return failures({ recurringPayment: 'not-set-up' })
41
+ context.pageData.errorRedirect = true
42
+ context.redirectUri = CANCEL_RP_LICENCE_NOT_FOUND.uri
43
+ } else if (!authenticationResult.recurringPayment) {
44
+ context.pageData.errorRedirect = true
45
+ context.redirectUri = CANCEL_RP_AGREEMENT_NOT_FOUND.uri
46
+ } else if (authenticationResult.recurringPayment.cancelledDate) {
47
+ context.pageData.errorRedirect = true
48
+ context.redirectUri = CANCEL_RP_ALREADY_CANCELLED.uri
49
+ context.pageData.payload = {
50
+ ...context.pageData.payload,
51
+ endDate: moment(authenticationResult.recurringPayment.endDate).format(cacheDateFormat)
52
+ }
46
53
  }
47
- if (authenticationResult.recurringPayment.cancelledDate) {
48
- return failures({ recurringPayment: 'rcp-cancelled' })
54
+
55
+ if (context.pageData.error || context.pageData.errorRedirect) {
56
+ return applyAuthFailure(request, h, context)
49
57
  }
50
58
 
51
59
  await setupCancelRecurringPaymentCacheFromAuthResult(request, authenticationResult)
@@ -18,7 +18,8 @@ import {
18
18
  LICENCE_SUMMARY,
19
19
  NAME,
20
20
  TERMS_AND_CONDITIONS,
21
- CHOOSE_PAYMENT
21
+ CHOOSE_PAYMENT,
22
+ JOURNEY_GOAL
22
23
  } from '../uri.js'
23
24
 
24
25
  import dateOfBirth from '../pages/concessions/date-of-birth/result-function.js'
@@ -38,6 +39,7 @@ import addressEntry from '../pages/contact/address/entry/result-function.js'
38
39
  import licenceSummary from '../pages/summary/licence-summary/result-function.js'
39
40
  import termsAndConditions from '../pages/terms-and-conditions/result-function.js'
40
41
  import choosePayment from '../pages/recurring-payments/choose-payment/result-function.js'
42
+ import journeyGoal from '../pages/journey-goal/result-function.js'
41
43
 
42
44
  /**
43
45
  * The result function determines the navigation in the route definition
@@ -59,5 +61,6 @@ export default {
59
61
  [NAME.page]: name,
60
62
  [LICENCE_SUMMARY.page]: licenceSummary,
61
63
  [TERMS_AND_CONDITIONS.page]: termsAndConditions,
62
- [CHOOSE_PAYMENT.page]: choosePayment
64
+ [CHOOSE_PAYMENT.page]: choosePayment,
65
+ [JOURNEY_GOAL.page]: journeyGoal
63
66
  }
@@ -440,6 +440,10 @@
440
440
  "licence_not_found_body_ea_link": "enquiries@environment-agency.gov.uk",
441
441
  "licence_not_found_body_3": " neu ffonio 03708 506 506 (8am - 6pm o ddydd Llun i ddydd Gwener, ac eithrio gwyliau cyhoeddus). ",
442
442
  "licence_not_found_body_call_charges_link": "Gallwch weld costau’r galwadau yma (yn agor mewn tab newydd)",
443
+ "licence_not_found_rp_body_1": "If you keep seeing this page you can cancel your recurring card payment by:",
444
+ "licence_not_found_rp_bullet_point_1": "emailing ",
445
+ "licence_not_found_rp_bullet_point_1_2": " up to 15 days before your payment date",
446
+ "licence_not_found_rp_bullet_point_2": "calling 03708 506 506 (8am to 6pm, Monday to Friday, except public holidays) up to the day before your payment date.",
443
447
  "licence_start_days": " diwrnod nesaf",
444
448
  "licence_start_enter_todays_date": "Rhowch ddyddiad heddiw os ydych chi am i’r drwydded 1 diwrnod neu 8 diwrnod ddechrau yn hwyrach heddiw.",
445
449
  "licence_start_error_date_real": "Mae’n rhaid i ddyddiad dechrau’r drwydded fod yn ddyddiad dilys",
@@ -605,14 +609,14 @@
605
609
  "order_complete_when_fishing_title": "Wrth bysgota",
606
610
  "order_complete_title_application": "Cais wedi’i gwblhau",
607
611
  "order_complete_title_payment": "Taliad wedi’i gwblhau: ",
608
- "ordnance_body_1": "Addressing information and mapping data from Ordnance Survey is © Crown copyright and database rights 2016",
609
- "ordnance_body_2": " 100024198. Use of this data is subject to the following conditions by way of exception to the standard Open Government Licence referred to at the foot of this page:",
610
- "ordnance_body_bulletpoint_1": "You are granted a non-exclusive, royalty free revocable licence solely to view the licensed mapping and addressing data for non-commercial purposes for the period during which we make it available;",
611
- "ordnance_body_bulletpoint_2": "You are not permitted to copy, sub-license, distribute, sell or otherwise make available such data to third parties in any form; and",
612
- "ordnance_body_bulletpoint_3": "Third party rights to enforce the terms of this licence shall be reserved to OS.",
612
+ "ordnance_body_1": "Mae gwybodaeth cyfeiriadau a data mapio gan yr Arolwg Ordnans yn unol â hawlfraint y Goron a hawliau cronfeydd data 2022",
613
+ "ordnance_body_2": " 100024198. Rydych yn defnyddio’r data hwn yn unol â’r amodau canlynol fel eithriad i’r Drwydded Lywodraeth Agored safonol y cyfeirir ati ar waelod y dudalen hon:",
614
+ "ordnance_body_bulletpoint_1": "Rhoddir trwydded ddirymiadwy, anghyfyngedig a heb freindal i chi i weld y data mapio a chyfeiriadau trwyddedig at ddibenion anfasnachol am y cyfnod yr ydym yn ei darparu;",
615
+ "ordnance_body_bulletpoint_2": "Ni chewch gopïo, is-drwyddedu, dosbarthu na gwerthu unrhyw ran o’r data hwn i drydydd partïon mewn unrhyw ffurf; a",
616
+ "ordnance_body_bulletpoint_3": "Bydd yr Arolwg Ordnans yn cadw’r hawlio trydydd parti i orfodi amodau’r drwydded hon.",
613
617
  "ordnance_body_link": "OS (yn agor ar dudalen newydd)",
614
- "ordnance_subheading": "Ordnance Survey terms and conditions",
615
- "ordnance_title": "Ordnance Survey terms and conditions - GOV.UK",
618
+ "ordnance_subheading": "Yr Arolwg Ordnans telerau ac amodau",
619
+ "ordnance_title": "Yr Arolwg Ordnans telerau ac amodau",
616
620
  "our_address_1": "Asiantaeth yr Amgylchedd",
617
621
  "our_address_2": "Horizon House",
618
622
  "our_address_3": "Deanery Road",
@@ -786,7 +790,29 @@
786
790
  "role_required_body_1": "You were successfully signed in but you do not have the correct role assigned to access the telesales application.",
787
791
  "role_required_body_2": "Please contact your Microsoft Dynamics administrator to request access.",
788
792
  "role_required_title": "Role required",
793
+ "rp_licence_already_cancelled_heading": "Your recurring card payment agreement is already cancelled",
794
+ "rp_licence_already_cancelled_body_1": "Licence ending ",
795
+ "rp_licence_already_cancelled_body_1_1": " expires on ",
796
+ "rp_licence_already_cancelled_body_1_2": " and will not renew automatically. To continue fishing after this date you need to ",
797
+ "rp_licence_already_cancelled_body_link": "get a new licence (opens in new tab)",
798
+ "rp_licence_already_cancelled_body_2_1": "If you need help email ",
799
+ "rp_licence_already_cancelled_body_2_2": " or call 03708 506 506 (8am to 6pm, Monday to Friday, except public holidays).",
800
+ "rp_licence_already_cancelled_body_3_1": "Go back",
801
+ "rp_licence_already_cancelled_body_3_2": " to cancel the recurring card payment for a different licence.",
802
+ "rp_licence_already_cancelled_body_ea_link": "enquiries@environment-agency.gov.uk",
803
+ "rp_cancel_already_cancelled_title": "Already cancelled - Cancel your recurring card payment ",
789
804
  "rp_cancel_complete_title": "Cancel your recurring card payment agreement - complete",
805
+ "rp_cancel_identify_title": "Cancel your recurring card payment agreement - identify",
806
+ "rp_cancel_no_agreement_found_title": "Agreement not found - Cancel your recurring card payment",
807
+ "rp_cancel_no_agreement_found_heading": "There is no recurring card payment linked to this licence",
808
+ "rp_cancel_no_agreement_found_licence_will_not_renew_1": "Licence ending ",
809
+ "rp_cancel_no_agreement_found_licence_will_not_renew_2": " will not renew automatically.",
810
+ "rp_cancel_no_agreement_found_go_back_link": "Go back",
811
+ "rp_cancel_no_agreement_found_go_back_instruction": " to cancel the recurring card payment for a different licence.",
812
+ "rp_cancel_no_agreement_found_need_help_1": "If you need help email ",
813
+ "rp_cancel_no_agreement_found_need_help_email": "enquiries@environment-agency.gov.uk",
814
+ "rp_cancel_no_agreement_found_need_help_2": " or call 03708 506 506 (8am to 6pm, Monday to Friday, except public holidays). ",
815
+ "rp_cancel_no_agreement_found_call_charges_link": "View call charges (opens in new tab).",
790
816
  "rp_cancel_confirm_accept": "Yes, cancel my recurring payment agreement",
791
817
  "rp_cancel_confirm_body": "Your current licence will reman valid until it expires on ",
792
818
  "rp_cancel_confirm_reject": "No, I've changed my mind",
@@ -389,6 +389,18 @@
389
389
  "important_info_contact_post": "Post",
390
390
  "important_info_contact_title_other": "How should we contact the licence holder about updates affecting their licence?",
391
391
  "important_info_contact_title_you": "How should we contact you about updates affecting your licence?",
392
+ "journey_goal_title": "What do you wish to do?",
393
+ "journey_goal_heading": "What do you wish to do?",
394
+ "journey_goal_error": "Please select what you wish to do",
395
+ "journey_goal_get_new_licence": "Get a new licence",
396
+ "journey_goal_renew_existing_licence": "Renew a 12-month licence",
397
+ "journey_goal_renew_existing_licence_proviso": "For licences that expired in the last 30 days",
398
+ "journey_goal_you_will_need": "You will need",
399
+ "journey_goal_cancel_recurring_payment": "Cancel a recurring card payment",
400
+ "journey_goal_instructions_req_1": "the last 6 characters of your licence number",
401
+ "journey_goal_instructions_req_2": "your date of birth",
402
+ "journey_goal_instructions_req_3": "your postcode",
403
+ "journey_goal_": "",
392
404
  "licence_1_day": "1-day",
393
405
  "licence_8_day": "8-day",
394
406
  "licence_12_month": "12-month",
@@ -439,6 +451,10 @@
439
451
  "licence_not_found_body_ea_link": "enquiries@environment-agency.gov.uk",
440
452
  "licence_not_found_body_3": " or calling 03708 506 506 (8am to 6pm, Monday to Friday, except public holidays). ",
441
453
  "licence_not_found_body_call_charges_link": "View call charges (opens in new tab)",
454
+ "licence_not_found_rp_body_1": "If you keep seeing this page you can cancel your recurring card payment by:",
455
+ "licence_not_found_rp_bullet_point_1": "emailing ",
456
+ "licence_not_found_rp_bullet_point_1_2": " up to 15 days before your payment date",
457
+ "licence_not_found_rp_bullet_point_2": "calling 03708 506 506 (8am to 6pm, Monday to Friday, except public holidays) up to the day before your payment date.",
442
458
  "licence_num": "Licence number",
443
459
  "licence_start_days": " days",
444
460
  "licence_start_enter_todays_date": "Enter today’s date if you want the 1-day or 8-day licence to start later today.",
@@ -786,7 +802,29 @@
786
802
  "role_required_body_1": "You were successfully signed in but you do not have the correct role assigned to access the telesales application.",
787
803
  "role_required_body_2": "Please contact your Microsoft Dynamics administrator to request access.",
788
804
  "role_required_title": "Role required",
805
+ "rp_licence_already_cancelled_heading": "Your recurring card payment agreement is already cancelled",
806
+ "rp_licence_already_cancelled_body_1": "Licence ending ",
807
+ "rp_licence_already_cancelled_body_1_1": " expires on ",
808
+ "rp_licence_already_cancelled_body_1_2": " and will not renew automatically. To continue fishing after this date you need to ",
809
+ "rp_licence_already_cancelled_body_link": "get a new licence (opens in new tab)",
810
+ "rp_licence_already_cancelled_body_2_1": "If you need help email ",
811
+ "rp_licence_already_cancelled_body_2_2": " or call 03708 506 506 (8am to 6pm, Monday to Friday, except public holidays).",
812
+ "rp_licence_already_cancelled_body_3_1": "Go back",
813
+ "rp_licence_already_cancelled_body_3_2": " to cancel the recurring card payment for a different licence.",
814
+ "rp_licence_already_cancelled_body_ea_link": "enquiries@environment-agency.gov.uk",
815
+ "rp_cancel_already_cancelled_title": "Already cancelled - Cancel your recurring card payment ",
789
816
  "rp_cancel_complete_title": "Cancel your recurring card payment agreement - complete",
817
+ "rp_cancel_identify_title": "Cancel your recurring card payment agreement - identify",
818
+ "rp_cancel_no_agreement_found_title": "Agreement not found - Cancel your recurring card payment",
819
+ "rp_cancel_no_agreement_found_heading": "There is no recurring card payment linked to this licence",
820
+ "rp_cancel_no_agreement_found_licence_will_not_renew_1": "Licence ending ",
821
+ "rp_cancel_no_agreement_found_licence_will_not_renew_2": " will not renew automatically.",
822
+ "rp_cancel_no_agreement_found_go_back_link": "Go back",
823
+ "rp_cancel_no_agreement_found_go_back_instruction": " to cancel the recurring card payment for a different licence.",
824
+ "rp_cancel_no_agreement_found_need_help_1": "If you need help email ",
825
+ "rp_cancel_no_agreement_found_need_help_email": "enquiries@environment-agency.gov.uk",
826
+ "rp_cancel_no_agreement_found_need_help_2": " or call 03708 506 506 (8am to 6pm, Monday to Friday, except public holidays). ",
827
+ "rp_cancel_no_agreement_found_call_charges_link": "View call charges (opens in new tab).",
790
828
  "rp_cancel_confirm_accept": "Yes, cancel my recurring payment agreement",
791
829
  "rp_cancel_confirm_body": "Your current licence will reman valid until it expires on ",
792
830
  "rp_cancel_confirm_reject": "No, I've changed my mind",
@@ -0,0 +1,33 @@
1
+ import resultFunction from '../result-function.js'
2
+
3
+ describe('resultFunction', () => {
4
+ const getMockRequest = journeyGoal => ({
5
+ payload: {
6
+ 'journey-goal': journeyGoal
7
+ }
8
+ })
9
+ it.each(['purchase-permission', 'renew-permission', 'cancel-recurring-payment'])(
10
+ 'returns journey goal for recognised journey goal - %s',
11
+ async journeyGoal => {
12
+ const mockRequest = getMockRequest(journeyGoal)
13
+ const result = await resultFunction(mockRequest)
14
+ expect(result).toBe(journeyGoal)
15
+ }
16
+ )
17
+
18
+ describe.each(['invalid-goal', 'unknown-journey-goal'])('handles unrecognised journey goal - %s', journeyGoal => {
19
+ it('returns null for unrecognised journey goal', async () => {
20
+ const mockRequest = getMockRequest(journeyGoal)
21
+ const result = await resultFunction(mockRequest)
22
+ expect(result).toBeNull()
23
+ })
24
+
25
+ it('logs an error for unrecognised journey goal', async () => {
26
+ const consoleErrorSpy = jest.spyOn(console, 'error')
27
+ const mockRequest = getMockRequest(journeyGoal)
28
+ await resultFunction(mockRequest)
29
+ expect(consoleErrorSpy).toHaveBeenCalledWith('Unknown journey goal selected:', journeyGoal)
30
+ consoleErrorSpy.mockRestore()
31
+ })
32
+ })
33
+ })
@@ -0,0 +1,50 @@
1
+ import pageRoute from '../../../routes/page-route.js'
2
+ import { JOURNEY_GOAL } from '../../../uri.js'
3
+ import { nextPage } from '../../../routes/next-page.js'
4
+ import { journeyGoalResults } from '../result-function.js'
5
+ import '../route.js'
6
+
7
+ jest.mock('../../../routes/page-route.js')
8
+ jest.mock('../../../uri.js', () => ({
9
+ ...jest.requireActual('../../../uri.js'),
10
+ JOURNEY_GOAL: { page: 'journey/goal/page', uri: Symbol('/journey/goal/page') }
11
+ }))
12
+ jest.mock('../../../routes/next-page.js')
13
+ jest.mock('../result-function.js', () => ({
14
+ journeyGoalResults: {
15
+ PURCHASE_PERMISSION: Symbol('purchase-permission'),
16
+ RENEW_PERMISSION: Symbol('renew-permission'),
17
+ CANCEL_RECURRING_PAYMENT: Symbol('cancel-recurring-payment')
18
+ }
19
+ }))
20
+
21
+ const getData = pageRoute.mock.calls[0][4]
22
+
23
+ describe('Journey Goal Page Route', () => {
24
+ it('passes JOURNEY_GOAL.page as view', () => {
25
+ expect(pageRoute).toHaveBeenCalledWith(JOURNEY_GOAL.page, expect.anything(), expect.anything(), expect.anything(), expect.anything())
26
+ })
27
+
28
+ it('passes JOURNEY_GOAL.uri as path', () => {
29
+ expect(pageRoute).toHaveBeenCalledWith(expect.anything(), JOURNEY_GOAL.uri, expect.anything(), expect.anything(), expect.anything())
30
+ })
31
+
32
+ it('passes function as validator', () => {
33
+ expect(pageRoute).toHaveBeenCalledWith(expect.anything(), expect.anything(), expect.any(Function), expect.anything(), expect.anything())
34
+ })
35
+
36
+ it('passes nextPage function as completion function', () => {
37
+ expect(pageRoute).toHaveBeenCalledWith(expect.anything(), expect.anything(), expect.anything(), nextPage, expect.anything())
38
+ })
39
+
40
+ it('passes function as getData parameter', () => {
41
+ expect(pageRoute).toHaveBeenCalledWith(expect.anything(), expect.anything(), expect.anything(), expect.anything(), expect.any(Function))
42
+ })
43
+
44
+ describe('getData', () => {
45
+ it('returns journey goal data', async () => {
46
+ const data = await getData()
47
+ expect(data).toEqual(expect.objectContaining({ journeyGoals: journeyGoalResults }))
48
+ })
49
+ })
50
+ })
@@ -0,0 +1,52 @@
1
+ {% extends "standard-form.njk" %}
2
+
3
+ {% from "radios/macro.njk" import govukRadios %}
4
+
5
+ {% set title = mssgs.journey_goal_title %}
6
+ {% set errorMsg = mssgs.journey_goal_error %}
7
+
8
+ {% set instructions %}
9
+ <p class="govuk-body-m">{{ mssgs.journey_goal_you_will_need }}</p>
10
+ <ul class="govuk-list govuk-list--bullet">
11
+ <li>{{ mssgs.journey_goal_instructions_req_1 }}</li>
12
+ <li>{{ mssgs.journey_goal_instructions_req_2 }}</li>
13
+ <li>{{ mssgs.journey_goal_instructions_req_3 }}</li>
14
+ </ul>
15
+ {% endset %}
16
+
17
+ {% block pageContent %}
18
+ {{ govukRadios({
19
+ idPrefix: 'journey-goal',
20
+ name: "journey-goal",
21
+ items: [
22
+ {
23
+ "id": "selector-buy-licence",
24
+ value: data.journeyGoals.PURCHASE_PERMISSION,
25
+ text: mssgs.journey_goal_get_new_licence,
26
+ checked: payload['journey-goal'] === data.journeyGoals.PURCHASE_PERMISSION
27
+ },
28
+ {
29
+ "id": "selector-renew-licence",
30
+ value: data.journeyGoals.RENEW_PERMISSION,
31
+ text: mssgs.journey_goal_renew_existing_licence,
32
+ checked: payload['journey-goal'] === data.journeyGoals.RENEW_PERMISSION,
33
+ hint: {
34
+ text: mssgs.journey_goal_renew_existing_licence_proviso
35
+ },
36
+ conditional: {
37
+ html: instructions
38
+ }
39
+ },
40
+ {
41
+ "id": "selector-cancel-recurring-payment",
42
+ value: data.journeyGoals.CANCEL_RECURRING_PAYMENT,
43
+ text: mssgs.journey_goal_cancel_recurring_payment,
44
+ checked: payload['journey-goal'] === data.journeyGoals.CANCEL_RECURRING_PAYMENT,
45
+ conditional: {
46
+ html: instructions
47
+ }
48
+ }
49
+ ],
50
+ errorMessage: { text: errorMsg } if error['journey-goal']
51
+ }) }}
52
+ {% endblock %}
@@ -0,0 +1,21 @@
1
+ export const journeyGoalResults = Object.freeze({
2
+ PURCHASE_PERMISSION: 'purchase-permission',
3
+ RENEW_PERMISSION: 'renew-permission',
4
+ CANCEL_RECURRING_PAYMENT: 'cancel-recurring-payment'
5
+ })
6
+
7
+ const journeyGoalResult = async request => {
8
+ switch (request.payload['journey-goal']) {
9
+ case 'purchase-permission':
10
+ return journeyGoalResults.PURCHASE_PERMISSION
11
+ case 'renew-permission':
12
+ return journeyGoalResults.RENEW_PERMISSION
13
+ case 'cancel-recurring-payment':
14
+ return journeyGoalResults.CANCEL_RECURRING_PAYMENT
15
+ default:
16
+ console.error('Unknown journey goal selected:', request.payload['journey-goal'])
17
+ return null
18
+ }
19
+ }
20
+
21
+ export default journeyGoalResult
@@ -0,0 +1,10 @@
1
+ import pageRoute from '../../routes/page-route.js'
2
+ import { JOURNEY_GOAL } from '../../uri.js'
3
+ import { nextPage } from '../../routes/next-page.js'
4
+ import { journeyGoalResults } from './result-function.js'
5
+
6
+ const getData = async () => ({
7
+ journeyGoals: journeyGoalResults
8
+ })
9
+
10
+ export default pageRoute(JOURNEY_GOAL.page, JOURNEY_GOAL.uri, () => {}, nextPage, getData)