diff --git a/cypress/e2e/donor/lpa-type.cy.js b/cypress/e2e/donor/lpa-type.cy.js index 77e3c1adec..c81c261a2b 100644 --- a/cypress/e2e/donor/lpa-type.cy.js +++ b/cypress/e2e/donor/lpa-type.cy.js @@ -7,7 +7,7 @@ describe('LPA type', () => { cy.checkA11yApp(); cy.contains('button', 'Continue').click(); - cy.url().should('contain', '/application-reason'); + cy.url().should('contain', '/task-list'); }); it('errors when unselected', () => { diff --git a/cypress/e2e/donor/previous-application-number.cy.js b/cypress/e2e/donor/previous-application-number.cy.js index c9d15df24b..34177b924e 100644 --- a/cypress/e2e/donor/previous-application-number.cy.js +++ b/cypress/e2e/donor/previous-application-number.cy.js @@ -1,23 +1,35 @@ describe('Previous application number', () => { - it('can be submitted', () => { + beforeEach(() => { cy.visit('/fixtures?redirect=/previous-application-number'); + }); + + it('can be submitted', () => { cy.checkA11yApp(); - cy.get('#f-previous-application-number').type('ABC'); + cy.get('#f-previous-application-number').type('MABC'); + cy.contains('button', 'Save and continue').click(); - cy.contains('button', 'Continue').click(); - cy.url().should('contain', '/task-list'); + cy.url().should('contain', '/what-happens-after-no-fee'); }); it('errors when unselected', () => { - cy.visit('/fixtures?redirect=/previous-application-number'); + cy.contains('button', 'Save and continue').click(); - cy.contains('button', 'Continue').click(); + cy.get('.govuk-error-summary').within(() => { + cy.contains('Enter previous reference number'); + }); + + cy.contains('.govuk-error-message', 'Enter previous reference number'); + }); + + it('errors when not correct format', () => { + cy.get('#f-previous-application-number').type('ABC'); + cy.contains('button', 'Save and continue').click(); cy.get('.govuk-error-summary').within(() => { - cy.contains('Enter previousApplicationNumber'); + cy.contains('Previous reference number must begin with 7 or M'); }); - cy.contains('.govuk-fieldset .govuk-error-message', 'Enter previousApplicationNumber'); + cy.contains('.govuk-error-message', 'Previous reference number must begin with 7 or M'); }); }); diff --git a/internal/page/donor/previous_application_number.go b/internal/page/donor/previous_application_number.go index 191bb543bc..52a48bbe3e 100644 --- a/internal/page/donor/previous_application_number.go +++ b/internal/page/donor/previous_application_number.go @@ -4,7 +4,6 @@ import ( "net/http" "github.com/ministryofjustice/opg-go-common/template" - "github.com/ministryofjustice/opg-modernising-lpa/internal/actor" "github.com/ministryofjustice/opg-modernising-lpa/internal/page" "github.com/ministryofjustice/opg-modernising-lpa/internal/validation" ) @@ -30,16 +29,18 @@ func PreviousApplicationNumber(tmpl template.Template, donorStore DonorStore) Ha if data.Errors.None() { if lpa.PreviousApplicationNumber != data.Form.PreviousApplicationNumber { - lpa.HasSentApplicationUpdatedEvent = false lpa.PreviousApplicationNumber = data.Form.PreviousApplicationNumber - lpa.Tasks.YourDetails = actor.TaskCompleted if err := donorStore.Put(r.Context(), lpa); err != nil { return err } } - return appData.Redirect(w, r, lpa, page.Paths.TaskList.Format(lpa.ID)) + if lpa.PreviousApplicationNumber[0] == '7' { + return appData.Redirect(w, r, lpa, page.Paths.WhatWasYourOriginalFee.Format(lpa.ID)) + } else { + return appData.Redirect(w, r, lpa, page.Paths.WhatHappensAfterNoFee.Format(lpa.ID)) + } } } @@ -61,7 +62,8 @@ func (f *previousApplicationNumberForm) Validate() validation.List { var errors validation.List errors.String("previous-application-number", "previousApplicationNumber", f.PreviousApplicationNumber, - validation.Empty()) + validation.Empty(), + validation.ReferenceNumber()) return errors } diff --git a/internal/page/donor/previous_application_number_test.go b/internal/page/donor/previous_application_number_test.go index 5cf217fddf..d65368a234 100644 --- a/internal/page/donor/previous_application_number_test.go +++ b/internal/page/donor/previous_application_number_test.go @@ -7,7 +7,6 @@ import ( "strings" "testing" - "github.com/ministryofjustice/opg-modernising-lpa/internal/actor" "github.com/ministryofjustice/opg-modernising-lpa/internal/page" "github.com/ministryofjustice/opg-modernising-lpa/internal/validation" "github.com/stretchr/testify/assert" @@ -71,39 +70,46 @@ func TestGetPreviousApplicationNumberWhenTemplateErrors(t *testing.T) { } func TestPostPreviousApplicationNumber(t *testing.T) { - form := url.Values{ - "previous-application-number": {"ABC"}, + testcases := map[string]page.LpaPath{ + "7": page.Paths.WhatWasYourOriginalFee, + "M": page.Paths.WhatHappensAfterNoFee, } - w := httptest.NewRecorder() - r, _ := http.NewRequest(http.MethodPost, "/", strings.NewReader(form.Encode())) - r.Header.Add("Content-Type", page.FormUrlEncoded) - - donorStore := newMockDonorStore(t) - donorStore. - On("Put", r.Context(), &page.Lpa{ - ID: "lpa-id", - UID: "lpa-uid", - PreviousApplicationNumber: "ABC", - Tasks: page.Tasks{YourDetails: actor.TaskCompleted}, - }). - Return(nil) - - err := PreviousApplicationNumber(nil, donorStore)(testAppData, w, r, &page.Lpa{ - ID: "lpa-id", - UID: "lpa-uid", - HasSentApplicationUpdatedEvent: true, - }) - resp := w.Result() - - assert.Nil(t, err) - assert.Equal(t, http.StatusFound, resp.StatusCode) - assert.Equal(t, page.Paths.TaskList.Format("lpa-id"), resp.Header.Get("Location")) + for start, redirect := range testcases { + t.Run(start, func(t *testing.T) { + form := url.Values{ + "previous-application-number": {start}, + } + + w := httptest.NewRecorder() + r, _ := http.NewRequest(http.MethodPost, "/", strings.NewReader(form.Encode())) + r.Header.Add("Content-Type", page.FormUrlEncoded) + + donorStore := newMockDonorStore(t) + donorStore. + On("Put", r.Context(), &page.Lpa{ + ID: "lpa-id", + UID: "lpa-uid", + PreviousApplicationNumber: start, + }). + Return(nil) + + err := PreviousApplicationNumber(nil, donorStore)(testAppData, w, r, &page.Lpa{ + ID: "lpa-id", + UID: "lpa-uid", + }) + resp := w.Result() + + assert.Nil(t, err) + assert.Equal(t, http.StatusFound, resp.StatusCode) + assert.Equal(t, redirect.Format("lpa-id"), resp.Header.Get("Location")) + }) + } } func TestPostPreviousApplicationNumberWhenNotChanged(t *testing.T) { form := url.Values{ - "previous-application-number": {"ABC"}, + "previous-application-number": {"M-0000"}, } w := httptest.NewRecorder() @@ -113,18 +119,18 @@ func TestPostPreviousApplicationNumberWhenNotChanged(t *testing.T) { err := PreviousApplicationNumber(nil, nil)(testAppData, w, r, &page.Lpa{ ID: "lpa-id", UID: "lpa-uid", - PreviousApplicationNumber: "ABC", + PreviousApplicationNumber: "M-0000", }) resp := w.Result() assert.Nil(t, err) assert.Equal(t, http.StatusFound, resp.StatusCode) - assert.Equal(t, page.Paths.TaskList.Format("lpa-id"), resp.Header.Get("Location")) + assert.Equal(t, page.Paths.WhatHappensAfterNoFee.Format("lpa-id"), resp.Header.Get("Location")) } func TestPostPreviousApplicationNumberWhenStoreErrors(t *testing.T) { form := url.Values{ - "previous-application-number": {"ABC"}, + "previous-application-number": {"MABC"}, } w := httptest.NewRecorder() @@ -177,10 +183,21 @@ func TestPreviousApplicationNumberFormValidate(t *testing.T) { form *previousApplicationNumberForm errors validation.List }{ - "valid": { + "valid modernised": { + form: &previousApplicationNumberForm{ + PreviousApplicationNumber: "M", + }, + }, + "valid old": { + form: &previousApplicationNumberForm{ + PreviousApplicationNumber: "7", + }, + }, + "invalid": { form: &previousApplicationNumberForm{ - PreviousApplicationNumber: "A", + PreviousApplicationNumber: "x", }, + errors: validation.With("previous-application-number", validation.ReferenceNumberError{Label: "previousApplicationNumber"}), }, "empty": { form: &previousApplicationNumberForm{}, diff --git a/internal/page/donor/which_fee_type_are_you_applying_for.go b/internal/page/donor/which_fee_type_are_you_applying_for.go index 284a1cd285..addc0ed7b5 100644 --- a/internal/page/donor/which_fee_type_are_you_applying_for.go +++ b/internal/page/donor/which_fee_type_are_you_applying_for.go @@ -35,7 +35,11 @@ func WhichFeeTypeAreYouApplyingFor(tmpl template.Template, donorStore DonorStore return err } - return appData.Redirect(w, r, lpa, page.Paths.EvidenceRequired.Format(lpa.ID)) + if lpa.FeeType.IsRepeatApplicationFee() { + return appData.Redirect(w, r, lpa, page.Paths.PreviousApplicationNumber.Format(lpa.ID)) + } else { + return appData.Redirect(w, r, lpa, page.Paths.EvidenceRequired.Format(lpa.ID)) + } } } diff --git a/internal/page/donor/which_fee_type_are_you_applying_for_test.go b/internal/page/donor/which_fee_type_are_you_applying_for_test.go index e2c9823943..12d8250949 100644 --- a/internal/page/donor/which_fee_type_are_you_applying_for_test.go +++ b/internal/page/donor/which_fee_type_are_you_applying_for_test.go @@ -74,25 +74,36 @@ func TestGetWhichFeeTypeAreYouApplyingForOnTemplateError(t *testing.T) { } func TestPostWhichFeeTypeAreYouApplyingFor(t *testing.T) { - form := url.Values{ - "fee-type": {page.HalfFee.String()}, + testcases := map[page.FeeType]page.LpaPath{ + page.HalfFee: page.Paths.EvidenceRequired, + page.NoFee: page.Paths.EvidenceRequired, + page.HardshipFee: page.Paths.EvidenceRequired, + page.RepeatApplicationFee: page.Paths.PreviousApplicationNumber, } - w := httptest.NewRecorder() - r, _ := http.NewRequest(http.MethodPost, "/", strings.NewReader(form.Encode())) - r.Header.Add("Content-Type", page.FormUrlEncoded) + for feeType, redirect := range testcases { + t.Run(feeType.String(), func(t *testing.T) { + form := url.Values{ + "fee-type": {feeType.String()}, + } - donorStore := newMockDonorStore(t) - donorStore. - On("Put", r.Context(), &page.Lpa{ID: "lpa-id", FeeType: page.HalfFee}). - Return(nil) + w := httptest.NewRecorder() + r, _ := http.NewRequest(http.MethodPost, "/", strings.NewReader(form.Encode())) + r.Header.Add("Content-Type", page.FormUrlEncoded) - err := WhichFeeTypeAreYouApplyingFor(nil, donorStore)(testAppData, w, r, &page.Lpa{ID: "lpa-id"}) - resp := w.Result() + donorStore := newMockDonorStore(t) + donorStore. + On("Put", r.Context(), &page.Lpa{ID: "lpa-id", FeeType: feeType}). + Return(nil) - assert.Nil(t, err) - assert.Equal(t, page.Paths.EvidenceRequired.Format("lpa-id"), resp.Header.Get("Location")) - assert.Equal(t, http.StatusFound, resp.StatusCode) + err := WhichFeeTypeAreYouApplyingFor(nil, donorStore)(testAppData, w, r, &page.Lpa{ID: "lpa-id"}) + resp := w.Result() + + assert.Nil(t, err) + assert.Equal(t, redirect.Format("lpa-id"), resp.Header.Get("Location")) + assert.Equal(t, http.StatusFound, resp.StatusCode) + }) + } } func TestPostWhichFeeTypeAreYouApplyingForOnStoreError(t *testing.T) { diff --git a/internal/page/paths.go b/internal/page/paths.go index 40f7a9e63e..aaa0ab0f7b 100644 --- a/internal/page/paths.go +++ b/internal/page/paths.go @@ -173,6 +173,7 @@ type AppPaths struct { UseExistingAddress LpaPath WhatACertificateProviderDoes LpaPath WhatHappensAfterNoFee LpaPath + WhatWasYourOriginalFee LpaPath WhenCanTheLpaBeUsed LpaPath WhichFeeTypeAreYouApplyingFor LpaPath WithdrawThisLpa LpaPath @@ -313,6 +314,7 @@ var Paths = AppPaths{ UseExistingAddress: "/use-existing-address", WhatACertificateProviderDoes: "/what-a-certificate-provider-does", WhatHappensAfterNoFee: "/what-happens-after-no-fee", + WhatWasYourOriginalFee: "/what-was-your-original-fee", WhenCanTheLpaBeUsed: "/when-can-the-lpa-be-used", WhichFeeTypeAreYouApplyingFor: "/which-fee-type-are-you-applying-for", WithdrawThisLpa: "/withdraw-this-lpa", diff --git a/internal/validation/check.go b/internal/validation/check.go index edbcc13260..47ecc7d24c 100644 --- a/internal/validation/check.go +++ b/internal/validation/check.go @@ -360,3 +360,17 @@ func (c DateMustBePastCheck) CheckDate(label string, value date.Date) Formattabl func DateMustBePast() DateMustBePastCheck { return DateMustBePastCheck{} } + +type ReferenceNumberCheck struct{} + +func (c ReferenceNumberCheck) CheckString(label, value string) FormattableError { + if value[0] != 'M' && value[0] != '7' { + return ReferenceNumberError{Label: label} + } + + return nil +} + +func ReferenceNumber() ReferenceNumberCheck { + return ReferenceNumberCheck{} +} diff --git a/internal/validation/check_test.go b/internal/validation/check_test.go index 2edc7e95c0..11b5e611e4 100644 --- a/internal/validation/check_test.go +++ b/internal/validation/check_test.go @@ -195,6 +195,19 @@ func TestCheckString(t *testing.T) { checks: []StringChecker{Email()}, expected: With(name, EmailError{Label: label}), }, + "reference number modernised": { + input: "M", + checks: []StringChecker{ReferenceNumber()}, + }, + "reference number old": { + input: "7", + checks: []StringChecker{ReferenceNumber()}, + }, + "reference number invalid": { + input: "a", + checks: []StringChecker{ReferenceNumber()}, + expected: With(name, ReferenceNumberError{Label: label}), + }, } for scenario, tc := range testcases { diff --git a/internal/validation/error.go b/internal/validation/error.go index 9d39bd6203..5b585697d1 100644 --- a/internal/validation/error.go +++ b/internal/validation/error.go @@ -149,6 +149,16 @@ func (e DateMustBePastError) Format(l Localizer) string { }) } +type ReferenceNumberError struct { + Label string +} + +func (e ReferenceNumberError) Format(l Localizer) string { + return l.Format("errorReferenceNumber", map[string]any{ + "Label": l.T(e.Label), + }) +} + func lowerFirst(s string) string { r, n := utf8.DecodeRuneInString(s) return string(unicode.ToLower(r)) + s[n:] diff --git a/lang/cy.json b/lang/cy.json index 3a4e64b2c7..3a138278af 100644 --- a/lang/cy.json +++ b/lang/cy.json @@ -49,6 +49,7 @@ "errorSelect": "Dewiswch {{.Label}}", "errorEmail": "{{.Label}} Welsh", "errorPostcode": "{{.Label}} Welsh", + "errorReferenceNumber": "{{.Label}} Welsh", "donorMatchesActorWarning": "Welsh {{.FirstNames}} {{.LastName}} {{.Type}}", "attorneyMatchesActorWarning": "Welsh {{.FirstNames}} {{.LastName}} {{.Type}}", "attorneyMatchesAttorneyWarning": "Welsh {{.FirstNames}} {{.LastName}}", @@ -897,5 +898,10 @@ "youHaveWithdrawnLpaNumber": "Welsh {{.UID}}", "opgWillNowContactAnyoneWhoHasAlreadyBeenContacted": "Welsh", "withdrawn": "Welsh", - "dateLpaSigned": "Welsh" + "dateLpaSigned": "Welsh", + "whatIsYourPreviousReferenceNumber": "Welsh", + "whatIsYourPreviousReferenceNumberContent": "

Welsh

", + "whereCanFindReferenceNumber": "Welsh", + "whereCanFindReferenceNumberDetails": "

Welsh

", + "previousApplicationNumber": "Welsh" } diff --git a/lang/en.json b/lang/en.json index 3af9cf8257..f71d1fc267 100644 --- a/lang/en.json +++ b/lang/en.json @@ -50,6 +50,7 @@ "errorSelect": "Select {{.Label}}", "errorEmail": "{{.Label}} must be in the correct format, like name@example.com", "errorPostcode": "{{.Label}} must be a UK postcode", + "errorReferenceNumber": "{{.Label}} must begin with 7 or M", "donorMatchesActorWarning": "The donor’s name is also {{.FirstNames}} {{.LastName}}. The donor cannot be {{.Type}}.", "attorneyMatchesActorWarning": "There is also an attorney called {{.FirstNames}} {{.LastName}}. An attorney cannot be {{.Type}}.", "attorneyMatchesAttorneyWarning": "There is already an attorney called {{.FirstNames}} {{.LastName}}.", @@ -841,5 +842,10 @@ "youHaveWithdrawnLpaNumber": "You have withdrawn LPA number {{.UID}}.", "opgWillNowContactAnyoneWhoHasAlreadyBeenContacted": "OPG will now contact anyone who has already been contacted in relation to your LPA and notify them of your decision to withdraw.", "withdrawn": "Withdrawn", - "dateLpaSigned": "Date LPA signed" + "dateLpaSigned": "Date LPA signed", + "whatIsYourPreviousReferenceNumber": "What is your previous reference number?", + "whatIsYourPreviousReferenceNumberContent": "

You’ve told us that you recently made an LPA application.

We need your previous reference number so that we can match your old application to your new one.

", + "whereCanFindReferenceNumber": "Where can I find my reference number?", + "whereCanFindReferenceNumberDetails": "

Your reference number (also called ‘OPG reference number’ or ‘Our ref’) is on any letter you have from the Office of the Public Guardian.

It should also be on the cover letter we sent you when we sent your original application back to you.

", + "previousApplicationNumber": "Previous reference number" } diff --git a/web/template/previous_application_number.gohtml b/web/template/previous_application_number.gohtml index f38728e08e..791cb40a4b 100644 --- a/web/template/previous_application_number.gohtml +++ b/web/template/previous_application_number.gohtml @@ -1,23 +1,20 @@ {{ template "page" . }} -{{ define "pageTitle" }}{{ tr .App "previousApplicationNumber" }}{{ end }} +{{ define "pageTitle" }}{{ tr .App "whatIsYourPreviousReferenceNumber" }}{{ end }} {{ define "main" }}
-
-
-
- -

{{ tr .App "previousApplicationNumber" }}

-
- {{ template "error-message" (errorMessage . "previous-application-number") }} +

{{ tr .App "whatIsYourPreviousReferenceNumber" }}

+ + {{ trHtml .App "whatIsYourPreviousReferenceNumberContent" }} - {{ template "input" (input . "previous-application-number" "previousApplicationNumber" .Form.PreviousApplicationNumber "classes" "govuk-input--width-20") }} -
-
+ {{ template "details" (details . "whereCanFindReferenceNumber" "whereCanFindReferenceNumberDetails" false) }} + + + {{ template "input" (input . "previous-application-number" "previousApplicationNumber" .Form.PreviousApplicationNumber "labelClasses" "govuk-label--s" "classes" "govuk-input--width-20") }} - {{ template "continue-button" . }} + {{ template "save-and-return-buttons" . }} {{ template "csrf-field" . }}