diff --git a/docs/opg-status-change.json b/docs/opg-status-change.json new file mode 100644 index 00000000..a77e1ec5 --- /dev/null +++ b/docs/opg-status-change.json @@ -0,0 +1,10 @@ +{ + "type": "OPG_STATUS_CHANGE", + "changes": [ + { + "key": "/status", + "new": "cannot-register", + "old": "in-progress" + } + ] +} diff --git a/internal/shared/lpa.go b/internal/shared/lpa.go index 1e5bd7fb..3bc41a64 100644 --- a/internal/shared/lpa.go +++ b/internal/shared/lpa.go @@ -58,4 +58,9 @@ const ( LpaStatusRegistered = LpaStatus("registered") LpaStatusCannotRegister = LpaStatus("cannot-register") LpaStatusWithdrawn = LpaStatus("withdrawn") + LpaStatusCancelled = LpaStatus("cancelled") ) + +func (l LpaStatus) IsValid() bool { + return l == LpaStatusInProgress || l == LpaStatusStatutoryWaitingPeriod || l == LpaStatusRegistered || l == LpaStatusCannotRegister || l == LpaStatusWithdrawn || l == LpaStatusCancelled +} diff --git a/lambda/update/opg_change_status.go b/lambda/update/opg_change_status.go new file mode 100644 index 00000000..130082bc --- /dev/null +++ b/lambda/update/opg_change_status.go @@ -0,0 +1,45 @@ +package main + +import ( + "github.com/ministryofjustice/opg-data-lpa-store/internal/shared" + "github.com/ministryofjustice/opg-data-lpa-store/internal/validate" + "github.com/ministryofjustice/opg-data-lpa-store/lambda/update/parse" +) + +type OpgChangeStatus struct { + Status shared.LpaStatus +} + +func (r OpgChangeStatus) Apply(lpa *shared.Lpa) []shared.FieldError { + + if r.Status != shared.LpaStatusCannotRegister { + return []shared.FieldError{{Source: "/status", Detail: "Status to be updated should be cannot register"}} + } + + if lpa.Status == shared.LpaStatusRegistered { + return []shared.FieldError{{Source: "/status", Detail: "Lpa status cannot be registered"}} + } + + if lpa.Status == shared.LpaStatusCancelled { + return []shared.FieldError{{Source: "/status", Detail: "Lpa status cannot be cancelled"}} + } + + lpa.Status = r.Status + + return nil +} + +func validateOpgChangeStatus(changes []shared.Change, lpa *shared.Lpa) (OpgChangeStatus, []shared.FieldError) { + + var data OpgChangeStatus + + data.Status = lpa.Status + + errors := parse.Changes(changes). + Field("/status", &data.Status, parse.Validate(func() []shared.FieldError { + return validate.IsValid("", data.Status) + })). + Consumed() + + return data, errors +} diff --git a/lambda/update/opg_change_status_test.go b/lambda/update/opg_change_status_test.go new file mode 100644 index 00000000..ef83796a --- /dev/null +++ b/lambda/update/opg_change_status_test.go @@ -0,0 +1,94 @@ +package main + +import ( + "encoding/json" + "github.com/ministryofjustice/opg-data-lpa-store/internal/shared" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestOpgChangeStatusApply(t *testing.T) { + lpa := &shared.Lpa{ + Status: shared.LpaStatusInProgress, + } + c := OpgChangeStatus{ + Status: shared.LpaStatusCannotRegister, + } + + errors := c.Apply(lpa) + assert.Empty(t, errors) + assert.Equal(t, c.Status, lpa.Status) +} + +func TestOpgChangeStatusInvalidNewStatus(t *testing.T) { + lpa := &shared.Lpa{ + Status: shared.LpaStatusInProgress, + } + c := OpgChangeStatus{ + Status: shared.LpaStatusWithdrawn, + } + + errors := c.Apply(lpa) + assert.Equal(t, errors, []shared.FieldError{{Source: "/status", Detail: "Status to be updated should be cannot register"}}) +} + +func TestOpgChangeStatusIncorrectExistingStatus(t *testing.T) { + lpa := &shared.Lpa{ + Status: shared.LpaStatusRegistered, + } + c := OpgChangeStatus{ + Status: shared.LpaStatusCannotRegister, + } + + errors := c.Apply(lpa) + assert.Equal(t, errors, []shared.FieldError{{Source: "/status", Detail: "Lpa status cannot be registered"}}) +} + +func TestValidateUpdateOPGChangeStatus(t *testing.T) { + testcases := map[string]struct { + update shared.Update + lpa *shared.Lpa + errors []shared.FieldError + }{ + "valid - with previous values": { + update: shared.Update{ + Type: "OPG_STATUS_CHANGE", + Changes: []shared.Change{ + { + Key: "/status", + New: json.RawMessage(`"cannot-register"`), + Old: json.RawMessage(`"in-progress"`), + }, + }, + }, + lpa: &shared.Lpa{ + Status: shared.LpaStatusInProgress, + }, + }, + "invalid status": { + update: shared.Update{ + Type: "OPG_STATUS_CHANGE", + Changes: []shared.Change{ + { + Key: "/status", + New: json.RawMessage(`"never-register"`), + Old: json.RawMessage(`"in-progress"`), + }, + }, + }, + lpa: &shared.Lpa{ + Status: shared.LpaStatusInProgress, + }, + errors: []shared.FieldError{ + {Source: "/changes/0/new", Detail: "invalid value"}, + }, + }, + } + + for name, tc := range testcases { + t.Run(name, func(t *testing.T) { + _, errors := validateUpdate(tc.update, tc.lpa) + assert.ElementsMatch(t, tc.errors, errors) + }) + } +} diff --git a/lambda/update/parse/changes.go b/lambda/update/parse/changes.go index 69ccc197..b29a35b9 100644 --- a/lambda/update/parse/changes.go +++ b/lambda/update/parse/changes.go @@ -163,6 +163,13 @@ func oldEqualsExisting(old any, existing any) bool { return shared.IdentityCheckType(old.(string)) == *v + case *shared.LpaStatus: + if old == nil { + return *v == "" + } + + return shared.LpaStatus(old.(string)) == *v + case *string: if old == nil { return *v == "" diff --git a/lambda/update/validate.go b/lambda/update/validate.go index 1e925fb0..630b77b6 100644 --- a/lambda/update/validate.go +++ b/lambda/update/validate.go @@ -20,6 +20,8 @@ func validateUpdate(update shared.Update, lpa *shared.Lpa) (Applyable, []shared. return validateStatutoryWaitingPeriod(update.Changes) case "REGISTER": return validateRegister(update.Changes) + case "OPG_STATUS_CHANGE": + return validateOpgChangeStatus(update.Changes, lpa) case "TRUST_CORPORATION_SIGN": return validateTrustCorporationSign(update.Changes, lpa) case "DONOR_CONFIRM_IDENTITY":