Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
acsauk committed Dec 18, 2024
2 parents 2456352 + 50174ae commit bf7d042
Show file tree
Hide file tree
Showing 10 changed files with 231 additions and 31 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,8 @@ emit-evidence-received: ##@events emits an evidence-received event with the give
--function-name event-received text \
--payload '{"Records": [{"messageId": "19dd0b57-b21e-4ac1-bd88-01bbb068cb78", "body": "$(BODY)"}]}'

emit-reduced-fee-approved: ##@events emits a reduced-fee-approved event with the given LpaUID e.g. emit-reduced-fee-approved uid=abc-123
$(eval BODY := $(shell echo '{"version":"0","id":"abcdef01-2345-6789-abcd-ef0123456789","detail-type":"reduced-fee-approved","source":"opg.poas.sirius","account":"653761790766","time":"2024-01-01T12:00:00Z","region":"eu-west-1","resources":[],"detail":{"uid":"$(uid)"}}' | sed 's/"/\\"/g'))
emit-reduced-fee-approved: ##@events emits a reduced-fee-approved event with the given LpaUID and fee type e.g. emit-reduced-fee-approved uid=abc-123 type=HalfFee
$(eval BODY := $(shell echo '{"version":"0","id":"abcdef01-2345-6789-abcd-ef0123456789","detail-type":"reduced-fee-approved","source":"opg.poas.sirius","account":"653761790766","time":"2024-01-01T12:00:00Z","region":"eu-west-1","resources":[],"detail":{"uid":"$(uid)","approvedType": "$(type)"}}' | sed 's/"/\\"/g'))

docker compose -f docker/docker-compose.yml exec localstack awslocal lambda invoke \
--endpoint-url=http://localhost:4566 \
Expand Down
6 changes: 6 additions & 0 deletions cmd/event-received/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/ministryofjustice/opg-modernising-lpa/internal/document"
"github.com/ministryofjustice/opg-modernising-lpa/internal/dynamo"
"github.com/ministryofjustice/opg-modernising-lpa/internal/event"
"github.com/ministryofjustice/opg-modernising-lpa/internal/pay"
"github.com/ministryofjustice/opg-modernising-lpa/internal/random"
"github.com/ministryofjustice/opg-modernising-lpa/internal/s3"
"github.com/ministryofjustice/opg-modernising-lpa/internal/telemetry"
Expand Down Expand Up @@ -77,6 +78,11 @@ type uidEvent struct {
UID string `json:"uid"`
}

type feeApprovedEvent struct {
UID string `json:"uid"`
ApprovedType pay.FeeType `json:"approvedType"`
}

type dynamodbClient interface {
AllByKeys(ctx context.Context, keys []dynamo.Keys) ([]map[string]dynamodbtypes.AttributeValue, error)
AllByLpaUIDAndPartialSK(ctx context.Context, uid string, partialSK dynamo.SK, v any) error
Expand Down
6 changes: 4 additions & 2 deletions cmd/event-received/sirius_event_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func handleFeeApproved(
appData appcontext.Data,
now func() time.Time,
) error {
var v uidEvent
var v feeApprovedEvent
if err := json.Unmarshal(e.Detail, &v); err != nil {
return fmt.Errorf("failed to unmarshal detail: %w", err)
}
Expand All @@ -124,7 +124,9 @@ func handleFeeApproved(
return nil
}

if donor.FeeAmount() == 0 {
donor.FeeType = v.ApprovedType

if donor.FeeAmount() <= 0 {
donor.Tasks.PayForLpa = task.PaymentStateCompleted

if donor.Tasks.SignTheLpa.IsCompleted() {
Expand Down
168 changes: 159 additions & 9 deletions cmd/event-received/sirius_event_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ func TestHandleEvidenceReceivedWhenClientPutError(t *testing.T) {
func TestHandleFeeApproved(t *testing.T) {
e := &events.CloudWatchEvent{
DetailType: "reduced-fee-approved",
Detail: json.RawMessage(`{"uid":"M-1111-2222-3333"}`),
Detail: json.RawMessage(`{"uid":"M-1111-2222-3333","approvedType":"NoFee"}`),
}

donorProvided := donordata.Provided{
Expand Down Expand Up @@ -214,7 +214,7 @@ func TestHandleFeeApproved(t *testing.T) {
func TestHandleFeeApprovedWhenNotPaid(t *testing.T) {
event := &events.CloudWatchEvent{
DetailType: "reduced-fee-approved",
Detail: json.RawMessage(`{"uid":"M-1111-2222-3333"}`),
Detail: json.RawMessage(`{"uid":"M-1111-2222-3333","approvedType":"HalfFee"}`),
}

donorProvided := donordata.Provided{
Expand Down Expand Up @@ -283,7 +283,7 @@ func TestHandleFeeApprovedWhenNotPaid(t *testing.T) {
func TestHandleFeeApprovedWhenNotSigned(t *testing.T) {
event := &events.CloudWatchEvent{
DetailType: "reduced-fee-approved",
Detail: json.RawMessage(`{"uid":"M-1111-2222-3333"}`),
Detail: json.RawMessage(`{"uid":"M-1111-2222-3333","approvedType":"NoFee"}`),
}

donorProvided := donordata.Provided{
Expand Down Expand Up @@ -332,7 +332,7 @@ func TestHandleFeeApprovedWhenAlreadyPaidOrApproved(t *testing.T) {
t.Run(taskState.String(), func(t *testing.T) {
event := &events.CloudWatchEvent{
DetailType: "reduced-fee-approved",
Detail: json.RawMessage(`{"uid":"M-1111-2222-3333"}`),
Detail: json.RawMessage(`{"uid":"M-1111-2222-3333","approvedType":"NoFee"}`),
}

client := newMockDynamodbClient(t)
Expand All @@ -346,7 +346,7 @@ func TestHandleFeeApprovedWhenAlreadyPaidOrApproved(t *testing.T) {
client.
On("One", ctx, dynamo.LpaKey("123"), dynamo.DonorKey("456"), mock.Anything).
Return(func(ctx context.Context, pk dynamo.PK, sk dynamo.SK, v interface{}) error {
b, _ := attributevalue.Marshal(&donordata.Provided{
b, _ := attributevalue.Marshal(donordata.Provided{
PK: dynamo.LpaKey("123"),
SK: dynamo.LpaOwnerKey(dynamo.DonorKey("456")),
FeeType: pay.NoFee,
Expand All @@ -362,10 +362,160 @@ func TestHandleFeeApprovedWhenAlreadyPaidOrApproved(t *testing.T) {
}
}

func TestHandleFeeApprovedWhenApprovedTypeDiffers(t *testing.T) {
testcases := map[string]struct {
requestedFeeType pay.FeeType
requestedRepeatApplicationFee pay.CostOfRepeatApplication
previousFeeType pay.PreviousFee
approvedFeeType pay.FeeType
updatedTaskState task.PaymentState
payment donordata.Payment
}{
"Requested HalfFee, got QuarterFee": {
requestedFeeType: pay.HalfFee,
approvedFeeType: pay.QuarterFee,
updatedTaskState: task.PaymentStateCompleted,
payment: donordata.Payment{Amount: 4100},
},
"Requested HalfFee, got NoFee": {
requestedFeeType: pay.HalfFee,
approvedFeeType: pay.NoFee,
updatedTaskState: task.PaymentStateCompleted,
payment: donordata.Payment{Amount: 4100},
},
"Requested NoFee, got HalfFee": {
requestedFeeType: pay.NoFee,
approvedFeeType: pay.HalfFee,
updatedTaskState: task.PaymentStateApproved,
},
"Requested NoFee, got QuarterFee": {
requestedFeeType: pay.NoFee,
approvedFeeType: pay.QuarterFee,
updatedTaskState: task.PaymentStateApproved,
},
"Requested HalfFee RepeatApplicationFee (previously paid FullFee), got QuarterFee": {
requestedFeeType: pay.RepeatApplicationFee,
requestedRepeatApplicationFee: pay.CostOfRepeatApplicationHalfFee,
previousFeeType: pay.PreviousFeeFull,
approvedFeeType: pay.QuarterFee,
updatedTaskState: task.PaymentStateCompleted,
payment: donordata.Payment{Amount: 4100},
},
"Requested HalfFee RepeatApplicationFee (previously paid FullFee), got NoFee": {
requestedFeeType: pay.RepeatApplicationFee,
requestedRepeatApplicationFee: pay.CostOfRepeatApplicationHalfFee,
previousFeeType: pay.PreviousFeeFull,
approvedFeeType: pay.NoFee,
updatedTaskState: task.PaymentStateCompleted,
payment: donordata.Payment{Amount: 4100},
},
"Requested HalfFee RepeatApplicationFee (previously paid HalfFee), got QuarterFee": {
requestedFeeType: pay.RepeatApplicationFee,
requestedRepeatApplicationFee: pay.CostOfRepeatApplicationHalfFee,
previousFeeType: pay.PreviousFeeHalf,
approvedFeeType: pay.QuarterFee,
updatedTaskState: task.PaymentStateCompleted,
payment: donordata.Payment{Amount: 4100},
},
"Requested HalfFee RepeatApplicationFee (previously paid HalfFee), got NoFee": {
requestedFeeType: pay.RepeatApplicationFee,
requestedRepeatApplicationFee: pay.CostOfRepeatApplicationHalfFee,
previousFeeType: pay.PreviousFeeHalf,
approvedFeeType: pay.NoFee,
updatedTaskState: task.PaymentStateCompleted,
payment: donordata.Payment{Amount: 4100},
},
"Requested HalfFee RepeatApplicationFee (previously paid NoFee), got HalfFee": {
requestedFeeType: pay.RepeatApplicationFee,
requestedRepeatApplicationFee: pay.CostOfRepeatApplicationHalfFee,
previousFeeType: pay.PreviousFeeExemption,
approvedFeeType: pay.HalfFee,
updatedTaskState: task.PaymentStateApproved,
},
"Requested HalfFee RepeatApplicationFee (previously paid NoFee), got NoFee": {
requestedFeeType: pay.RepeatApplicationFee,
requestedRepeatApplicationFee: pay.CostOfRepeatApplicationHalfFee,
previousFeeType: pay.PreviousFeeExemption,
approvedFeeType: pay.NoFee,
updatedTaskState: task.PaymentStateCompleted,
},
"Requested NoFee RepeatApplicationFee, got HalfFee": {
requestedFeeType: pay.RepeatApplicationFee,
requestedRepeatApplicationFee: pay.CostOfRepeatApplicationNoFee,
approvedFeeType: pay.HalfFee,
updatedTaskState: task.PaymentStateApproved,
},
"Requested NoFee RepeatApplicationFee, got QuarterFee": {
requestedFeeType: pay.RepeatApplicationFee,
requestedRepeatApplicationFee: pay.CostOfRepeatApplicationNoFee,
approvedFeeType: pay.QuarterFee,
updatedTaskState: task.PaymentStateApproved,
},
"Requested HardshipFee, got HalfFee": {
requestedFeeType: pay.HardshipFee,
approvedFeeType: pay.HalfFee,
updatedTaskState: task.PaymentStateApproved,
},
"Requested HardshipFee, got QuarterFee": {
requestedFeeType: pay.HardshipFee,
approvedFeeType: pay.QuarterFee,
updatedTaskState: task.PaymentStateApproved,
},
}

for name, tc := range testcases {
t.Run(name, func(t *testing.T) {
event := &events.CloudWatchEvent{
DetailType: "reduced-fee-approved",
Detail: json.RawMessage(fmt.Sprintf(`{"uid":"M-1111-2222-3333","approvedType":"%s"}`, tc.approvedFeeType.String())),
}

donorProvided := &donordata.Provided{
PK: dynamo.LpaKey("123"),
SK: dynamo.LpaOwnerKey(dynamo.DonorKey("456")),
FeeType: tc.requestedFeeType,
Tasks: donordata.Tasks{PayForLpa: task.PaymentStatePending},
PaymentDetails: []donordata.Payment{tc.payment},
PreviousFee: tc.previousFeeType,
CostOfRepeatApplication: tc.requestedRepeatApplicationFee,
}

client := newMockDynamodbClient(t)
client.
On("OneByUID", ctx, "M-1111-2222-3333", mock.Anything).
Return(func(ctx context.Context, uid string, v interface{}) error {
b, _ := attributevalue.Marshal(dynamo.Keys{PK: dynamo.LpaKey("123"), SK: dynamo.LpaOwnerKey(dynamo.DonorKey("456"))})
attributevalue.Unmarshal(b, v)
return nil
})
client.
On("One", ctx, dynamo.LpaKey("123"), dynamo.DonorKey("456"), mock.Anything).
Return(func(ctx context.Context, pk dynamo.PK, sk dynamo.SK, v interface{}) error {
b, _ := attributevalue.Marshal(donorProvided)
attributevalue.Unmarshal(b, v)
return nil
})

updatedDonorProvided := *donorProvided
updatedDonorProvided.Tasks.PayForLpa = tc.updatedTaskState
updatedDonorProvided.FeeType = tc.approvedFeeType
updatedDonorProvided.UpdateHash()
updatedDonorProvided.UpdatedAt = testNow

client.EXPECT().
Put(ctx, &updatedDonorProvided).
Return(nil)

err := handleFeeApproved(ctx, client, event, nil, nil, nil, appcontext.Data{}, testNowFn)
assert.Nil(t, err)
})
}
}

func TestHandleFeeApprovedWhenDynamoClientPutError(t *testing.T) {
event := &events.CloudWatchEvent{
DetailType: "reduced-fee-approved",
Detail: json.RawMessage(`{"uid":"M-1111-2222-3333"}`),
Detail: json.RawMessage(`{"uid":"M-1111-2222-3333","approvedType":"NoFee"}`),
}

client := newMockDynamodbClient(t)
Expand Down Expand Up @@ -394,7 +544,7 @@ func TestHandleFeeApprovedWhenDynamoClientPutError(t *testing.T) {
func TestHandleFeeApprovedWhenShareCodeSenderError(t *testing.T) {
event := &events.CloudWatchEvent{
DetailType: "reduced-fee-approved",
Detail: json.RawMessage(`{"uid":"M-1111-2222-3333"}`),
Detail: json.RawMessage(`{"uid":"M-1111-2222-3333","approvedType":"NoFee"}`),
}

client := newMockDynamodbClient(t)
Expand Down Expand Up @@ -440,7 +590,7 @@ func TestHandleFeeApprovedWhenShareCodeSenderError(t *testing.T) {
func TestHandleFeeApprovedWhenEventClientError(t *testing.T) {
event := &events.CloudWatchEvent{
DetailType: "reduced-fee-approved",
Detail: json.RawMessage(`{"uid":"M-1111-2222-3333"}`),
Detail: json.RawMessage(`{"uid":"M-1111-2222-3333","approvedType":"NoFee"}`),
}

client := newMockDynamodbClient(t)
Expand Down Expand Up @@ -481,7 +631,7 @@ func TestHandleFeeApprovedWhenEventClientError(t *testing.T) {
func TestHandleFeeApprovedWhenLpaStoreError(t *testing.T) {
event := &events.CloudWatchEvent{
DetailType: "reduced-fee-approved",
Detail: json.RawMessage(`{"uid":"M-1111-2222-3333"}`),
Detail: json.RawMessage(`{"uid":"M-1111-2222-3333","approvedType":"NoFee"}`),
}

client := newMockDynamodbClient(t)
Expand Down
2 changes: 2 additions & 0 deletions internal/donor/donorpage/task_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ func taskListPaymentSection(provided *donordata.Provided) taskListSection {
paymentPath = donor.PathPayFee.Format(provided.LpaID)
case task.PaymentStateMoreEvidenceRequired:
paymentPath = donor.PathUploadEvidence.Format(provided.LpaID)
case task.PaymentStatePending, task.PaymentStateCompleted:
paymentPath = ""
default:
paymentPath = donor.PathAboutPayment.Format(provided.LpaID)
}
Expand Down
34 changes: 29 additions & 5 deletions internal/donor/donorpage/task_list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,30 @@ func TestGetTaskList(t *testing.T) {
return sections
},
},
"payment pending": {
appData: testAppData,
donor: &donordata.Provided{LpaID: "lpa-id", Donor: donordata.Donor{LastName: "a", Address: place.Address{Line1: "x"}}, Tasks: donordata.Tasks{PayForLpa: task.PaymentStatePending}},
evidenceReceived: true,
expected: func(sections []taskListSection) []taskListSection {
sections[1].Items = []taskListItem{
{Name: "payForTheLpa", Path: "", PaymentState: task.PaymentStatePending},
}

return sections
},
},
"payment completed": {
appData: testAppData,
donor: &donordata.Provided{LpaID: "lpa-id", Donor: donordata.Donor{LastName: "a", Address: place.Address{Line1: "x"}}, Tasks: donordata.Tasks{PayForLpa: task.PaymentStateCompleted}},
evidenceReceived: true,
expected: func(sections []taskListSection) []taskListSection {
sections[1].Items = []taskListItem{
{Name: "payForTheLpa", Path: "", PaymentState: task.PaymentStateCompleted},
}

return sections
},
},
"personal welfare": {
appData: testAppData,
donor: &donordata.Provided{LpaID: "lpa-id", Type: lpadata.LpaTypePersonalWelfare, Donor: donordata.Donor{LastName: "a", Address: place.Address{Line1: "x"}}},
Expand Down Expand Up @@ -462,7 +486,7 @@ func TestGetTaskList(t *testing.T) {
}

sections[1].Items = []taskListItem{
{Name: "payForTheLpa", Path: donor.PathAboutPayment.Format("lpa-id"), PaymentState: task.PaymentStateCompleted},
{Name: "payForTheLpa", Path: "", PaymentState: task.PaymentStateCompleted},
}

sections[2].Items = []taskListItem{
Expand Down Expand Up @@ -514,7 +538,7 @@ func TestGetTaskList(t *testing.T) {
}

sections[1].Items = []taskListItem{
{Name: "payForTheLpa", Path: donor.PathAboutPayment.Format("lpa-id"), PaymentState: task.PaymentStateCompleted},
{Name: "payForTheLpa", Path: "", PaymentState: task.PaymentStateCompleted},
}

sections[2].Items = []taskListItem{
Expand Down Expand Up @@ -567,7 +591,7 @@ func TestGetTaskList(t *testing.T) {
}

sections[1].Items = []taskListItem{
{Name: "payForTheLpa", Path: donor.PathAboutPayment.Format("lpa-id"), PaymentState: task.PaymentStateCompleted},
{Name: "payForTheLpa", Path: "", PaymentState: task.PaymentStateCompleted},
}

sections[2].Items = []taskListItem{
Expand Down Expand Up @@ -622,7 +646,7 @@ func TestGetTaskList(t *testing.T) {
}

sections[1].Items = []taskListItem{
{Name: "payForTheLpa", Path: donor.PathAboutPayment.Format("lpa-id"), PaymentState: task.PaymentStateCompleted},
{Name: "payForTheLpa", Path: "", PaymentState: task.PaymentStateCompleted},
}

sections[2].Items = []taskListItem{
Expand Down Expand Up @@ -678,7 +702,7 @@ func TestGetTaskList(t *testing.T) {
}

sections[1].Items = []taskListItem{
{Name: "payForTheLpa", Path: donor.PathAboutPayment.Format("lpa-id"), PaymentState: task.PaymentStateCompleted},
{Name: "payForTheLpa", Path: "", PaymentState: task.PaymentStateCompleted},
}

sections[2].Items = []taskListItem{
Expand Down
Loading

0 comments on commit bf7d042

Please sign in to comment.