Skip to content

Commit

Permalink
MLPAB-2416 MLPAB-2417 Trust corporation opt-out (#256)
Browse files Browse the repository at this point in the history
* Add test to show replacement attorney opt-out works
* Add trust corporation opt-out update
  • Loading branch information
hawx authored Sep 3, 2024
1 parent 9fadc87 commit 21f3626
Show file tree
Hide file tree
Showing 7 changed files with 244 additions and 161 deletions.
39 changes: 0 additions & 39 deletions internal/shared/lpa.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package shared

import (
"slices"
"time"
)

Expand All @@ -27,44 +26,6 @@ type LpaInit struct {
CertificateProviderNotRelatedConfirmedAt *time.Time `json:"certificateProviderNotRelatedConfirmedAt,omitempty"`
}

func (l *Lpa) GetAttorney(uid string) (Attorney, bool) {
idx := slices.IndexFunc(l.Attorneys, func(a Attorney) bool { return a.UID == uid })
if idx == -1 {
return Attorney{}, false
}

return l.Attorneys[idx], true
}

func (l *Lpa) PutAttorney(attorney Attorney) {
idx := slices.IndexFunc(l.Attorneys, func(a Attorney) bool { return a.UID == attorney.UID })
if idx == -1 {
l.Attorneys = append(l.Attorneys, attorney)
} else {
l.Attorneys[idx] = attorney
}
}

func (l *Lpa) ActiveAttorneys() (attorneys []Attorney) {
for _, a := range l.Attorneys {
if a.Status == AttorneyStatusActive {
attorneys = append(attorneys, a)
}
}

return attorneys
}

func (l *Lpa) ActiveTrustCorporations() (trustCorporations []TrustCorporation) {
for _, tc := range l.TrustCorporations {
if tc.Status == AttorneyStatusActive {
trustCorporations = append(trustCorporations, tc)
}
}

return trustCorporations
}

type Lpa struct {
LpaInit
Uid string `json:"uid"`
Expand Down
111 changes: 0 additions & 111 deletions internal/shared/lpa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,114 +19,3 @@ func TestLpaInitMarshalJSON(t *testing.T) {
data, _ := json.Marshal(LpaInit{})
assert.JSONEq(t, expected, string(data))
}

func TestAttorneysGet(t *testing.T) {
testCases := map[string]struct {
attorneys []Attorney
expectedAttorney Attorney
uid string
expectedFound bool
}{
"found": {
attorneys: []Attorney{
{Person: Person{UID: "abc", FirstNames: "a"}},
{Person: Person{UID: "xyz", FirstNames: "b"}},
},
expectedAttorney: Attorney{Person: Person{UID: "xyz", FirstNames: "b"}},
uid: "xyz",
expectedFound: true,
},
"not found": {
attorneys: []Attorney{
{Person: Person{UID: "abc", FirstNames: "a"}},
{Person: Person{UID: "xyz", FirstNames: "b"}},
},
expectedAttorney: Attorney{},
uid: "not-a-match",
expectedFound: false,
},
}

for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
lpa := &Lpa{LpaInit: LpaInit{Attorneys: tc.attorneys}}
a, found := lpa.GetAttorney(tc.uid)

assert.Equal(t, tc.expectedFound, found)
assert.Equal(t, tc.expectedAttorney, a)
})
}
}

func TestAttorneysPut(t *testing.T) {
testCases := map[string]struct {
attorneys []Attorney
expectedAttorneys []Attorney
updatedAttorney Attorney
}{
"does not exist": {
attorneys: []Attorney{
{Person: Person{UID: "abc", FirstNames: "a"}},
},
expectedAttorneys: []Attorney{
{Person: Person{UID: "abc", FirstNames: "a"}},
{Person: Person{UID: "xyz", FirstNames: "b"}},
},
updatedAttorney: Attorney{Person: Person{UID: "xyz", FirstNames: "b"}},
},
"exists": {
attorneys: []Attorney{
{Person: Person{UID: "abc", FirstNames: "a"}},
{Person: Person{UID: "xyz", FirstNames: "b"}},
},
expectedAttorneys: []Attorney{
{Person: Person{UID: "abc", FirstNames: "a"}},
{Person: Person{UID: "xyz", FirstNames: "z"}},
},
updatedAttorney: Attorney{Person: Person{UID: "xyz", FirstNames: "z"}},
},
}

for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
lpa := &Lpa{LpaInit: LpaInit{Attorneys: tc.attorneys}}
lpa.PutAttorney(tc.updatedAttorney)

assert.Equal(t, tc.expectedAttorneys, lpa.Attorneys)
})
}
}

func TestActiveAttorneys(t *testing.T) {
lpa := &Lpa{LpaInit: LpaInit{
Attorneys: []Attorney{
{Person: Person{FirstNames: "a"}},
{Person: Person{FirstNames: "b"}, Status: AttorneyStatusActive},
{Person: Person{FirstNames: "c"}, Status: AttorneyStatusReplacement},
{Person: Person{FirstNames: "d"}, Status: AttorneyStatusRemoved},
{Person: Person{FirstNames: "e"}, Status: AttorneyStatusActive},
},
}}

assert.Equal(t, []Attorney{
{Person: Person{FirstNames: "b"}, Status: AttorneyStatusActive},
{Person: Person{FirstNames: "e"}, Status: AttorneyStatusActive},
}, lpa.ActiveAttorneys())
}

func TestActiveTrustCorporations(t *testing.T) {
lpa := &Lpa{LpaInit: LpaInit{
TrustCorporations: []TrustCorporation{
{Name: "a"},
{Name: "b", Status: AttorneyStatusActive},
{Name: "c", Status: AttorneyStatusReplacement},
{Name: "d", Status: AttorneyStatusRemoved},
{Name: "e", Status: AttorneyStatusActive},
},
}}

assert.Equal(t, []TrustCorporation{
{Name: "b", Status: AttorneyStatusActive},
{Name: "e", Status: AttorneyStatusActive},
}, lpa.ActiveTrustCorporations())
}
21 changes: 10 additions & 11 deletions lambda/update/attorney_opt_out.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,18 @@ type AttorneyOptOut struct {
}

func (c AttorneyOptOut) Apply(lpa *shared.Lpa) []shared.FieldError {
attorney, ok := lpa.GetAttorney(c.AttorneyUID)
if !ok {
return []shared.FieldError{{Source: "/type", Detail: "attorney not found"}}
for i := range lpa.Attorneys {
if lpa.Attorneys[i].UID == c.AttorneyUID {
if lpa.Attorneys[i].SignedAt != nil && !lpa.Attorneys[i].SignedAt.IsZero() {
return []shared.FieldError{{Source: "/type", Detail: "attorney cannot opt out after signing"}}
}

lpa.Attorneys[i].Status = shared.AttorneyStatusRemoved
return nil
}
}

if attorney.SignedAt != nil && !attorney.SignedAt.IsZero() {
return []shared.FieldError{{Source: "/type", Detail: "attorney cannot opt out after signing"}}
}

attorney.Status = shared.AttorneyStatusRemoved
lpa.PutAttorney(attorney)

return nil
return []shared.FieldError{{Source: "/type", Detail: "attorney not found"}}
}

func validateAttorneyOptOut(update shared.Update) (AttorneyOptOut, []shared.FieldError) {
Expand Down
22 changes: 22 additions & 0 deletions lambda/update/attorney_opt_out_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,28 @@ func TestAttorneyOptOutApply(t *testing.T) {
},
},
},
"successful apply to replacement": {
lpa: &shared.Lpa{
Status: shared.LpaStatusInProgress,
LpaInit: shared.LpaInit{
Attorneys: []shared.Attorney{
{Person: shared.Person{UID: "a"}, Status: shared.AttorneyStatusActive},
{Person: shared.Person{UID: "b"}, Status: shared.AttorneyStatusReplacement},
{Person: shared.Person{UID: "c"}, Status: shared.AttorneyStatusActive},
},
},
},
expectedLpa: &shared.Lpa{
Status: shared.LpaStatusInProgress,
LpaInit: shared.LpaInit{
Attorneys: []shared.Attorney{
{Person: shared.Person{UID: "a"}, Status: shared.AttorneyStatusActive},
{Person: shared.Person{UID: "b"}, Status: shared.AttorneyStatusRemoved},
{Person: shared.Person{UID: "c"}, Status: shared.AttorneyStatusActive},
},
},
},
},
"not found": {
lpa: &shared.Lpa{
Status: shared.LpaStatusInProgress,
Expand Down
39 changes: 39 additions & 0 deletions lambda/update/trust_corporation_opt_out.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package main

import (
"github.com/ministryofjustice/opg-data-lpa-store/internal/shared"
"github.com/ministryofjustice/opg-data-lpa-store/internal/validate"
)

type TrustCorporationOptOut struct {
trustCorporationUID string
}

func (c TrustCorporationOptOut) Apply(lpa *shared.Lpa) []shared.FieldError {
for i := range lpa.TrustCorporations {
if lpa.TrustCorporations[i].UID == c.trustCorporationUID {
if len(lpa.TrustCorporations[i].Signatories) > 0 && !lpa.TrustCorporations[i].Signatories[0].SignedAt.IsZero() {
return []shared.FieldError{{Source: "/type", Detail: "trust corporation cannot opt out after signing"}}
}

lpa.TrustCorporations[i].Status = shared.AttorneyStatusRemoved
return nil
}
}

return []shared.FieldError{{Source: "/type", Detail: "trust corporation not found"}}
}

func validateTrustCorporationOptOut(update shared.Update) (TrustCorporationOptOut, []shared.FieldError) {
if len(update.Changes) > 0 {
return TrustCorporationOptOut{}, []shared.FieldError{{Source: "/changes", Detail: "expected empty"}}
}

author := update.Author.Details()

if errs := validate.UUID("/author", author.UID); len(errs) > 0 {
return TrustCorporationOptOut{}, errs
}

return TrustCorporationOptOut{trustCorporationUID: author.UID}, nil
}
Loading

0 comments on commit 21f3626

Please sign in to comment.