Skip to content

Commit 5b2989d

Browse files
CROSSLINK-303 Add closing action mapping
1 parent 3a522c8 commit 5b2989d

7 files changed

Lines changed: 94 additions & 17 deletions

File tree

broker/oapi/open-api.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,10 @@ components:
876876
type: string
877877
description: Name of the primary action for this state.
878878
Must be one of the actions defined in the actions array and is only meaningful when actions is present.
879+
closingAction:
880+
type: string
881+
description: Name of the closing action for this state.
882+
Must be one of the actions defined in the actions array.
879883
editable:
880884
type: boolean
881885
description: Indicates that a patron request can be updated in this state

broker/patron_request/service/action_mapping.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ type PatronRequestAction struct {
9090
}
9191

9292
type ActionMapping struct {
93+
StateModelName string
9394
borrowerStateActionMapping map[pr_db.PatronRequestState][]PatronRequestAction
9495
lenderStateActionMapping map[pr_db.PatronRequestState][]PatronRequestAction
9596
borrowerStateConfig map[pr_db.PatronRequestState]stateConfig
@@ -106,6 +107,7 @@ type stateConfig struct {
106107
autoActions []proapi.ModelAction
107108
terminal bool
108109
needsAttention bool
110+
closingAction *pr_db.PatronRequestAction
109111
}
110112

111113
// Constructor function to initialize the mappings for given StateModel
@@ -114,6 +116,7 @@ func NewActionMapping(stateModel *proapi.StateModel) *ActionMapping {
114116
if stateModel == nil || stateModel.States == nil {
115117
return r
116118
}
119+
r.StateModelName = stateModel.Name
117120

118121
borrowerMap := make(map[pr_db.PatronRequestState][]PatronRequestAction)
119122
lenderMap := make(map[pr_db.PatronRequestState][]PatronRequestAction)
@@ -134,6 +137,10 @@ func NewActionMapping(stateModel *proapi.StateModel) *ActionMapping {
134137
if state.NeedsAttention != nil && *state.NeedsAttention {
135138
currentStateConfig.needsAttention = true
136139
}
140+
if state.ClosingAction != nil && *state.ClosingAction != "" {
141+
closingAction := pr_db.PatronRequestAction(*state.ClosingAction)
142+
currentStateConfig.closingAction = &closingAction
143+
}
137144
actionEntries := make([]PatronRequestAction, 0)
138145
if state.Actions != nil {
139146
for _, action := range *state.Actions {
@@ -351,6 +358,14 @@ func (r *ActionMapping) IsTerminalState(pr pr_db.PatronRequest) bool {
351358
return ok && stateConfig.terminal
352359
}
353360

361+
func (r *ActionMapping) GetClosingAction(pr pr_db.PatronRequest) *pr_db.PatronRequestAction {
362+
config, ok := r.getStateConfig(pr)
363+
if !ok {
364+
return nil
365+
}
366+
return config.closingAction
367+
}
368+
354369
func (r *ActionMapping) getStateConfig(pr pr_db.PatronRequest) (stateConfig, bool) {
355370
if pr.Side == SideBorrowing {
356371
cfg, ok := r.borrowerStateConfig[pr.State]

broker/patron_request/service/action_mapping_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,32 @@ func TestGetEventTransitionRetryConditionalFromBorrowerWillSupply(t *testing.T)
255255
assert.Equal(t, BorrowerStateRetryPending, transition)
256256
}
257257

258+
func TestGetClosingAction(t *testing.T) {
259+
mapping := mustActionMapping(t)
260+
261+
action := mapping.GetClosingAction(pr_db.PatronRequest{Side: SideLending, State: LenderStateValidated})
262+
assert.NotNil(t, action)
263+
assert.Equal(t, LenderActionCannotSupply, *action)
264+
265+
action = mapping.GetClosingAction(pr_db.PatronRequest{Side: SideLending, State: LenderStateWillSupply})
266+
assert.NotNil(t, action)
267+
assert.Equal(t, LenderActionCannotSupply, *action)
268+
269+
action = mapping.GetClosingAction(pr_db.PatronRequest{Side: SideLending, State: LenderStateConditionPending})
270+
assert.NotNil(t, action)
271+
assert.Equal(t, LenderActionCannotSupply, *action)
272+
273+
action = mapping.GetClosingAction(pr_db.PatronRequest{Side: SideLending, State: LenderStateConditionAccepted})
274+
assert.NotNil(t, action)
275+
assert.Equal(t, LenderActionCannotSupply, *action)
276+
277+
action = mapping.GetClosingAction(pr_db.PatronRequest{Side: SideLending, State: LenderStateShipped})
278+
assert.Nil(t, action)
279+
280+
action = mapping.GetClosingAction(pr_db.PatronRequest{State: LenderStateWillSupply})
281+
assert.Nil(t, action)
282+
}
283+
258284
func listCompare(t *testing.T, list1 []pr_db.PatronRequestAction, list2 []pr_db.PatronRequestAction) {
259285
assert.Equal(t, len(list1), len(list2), "list1=%v, list2=%v", list1, list2)
260286
for i := range list1 {

broker/scheduler/service/batch_action.go

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,21 @@ const BATCH_COMP = "batch_action"
1818
const TIME_FORMAT = "2006-01-02 15:04:05"
1919

2020
type BatchActionService struct {
21-
eventBus events.EventBus
22-
prRepo pr_db.PrRepo
23-
emailSenderService *EmailSenderService
21+
eventBus events.EventBus
22+
prRepo pr_db.PrRepo
23+
emailSenderService *EmailSenderService
24+
actionMappingService prservice.ActionMappingService
2425
}
2526

2627
func NewBatchActionService(eventBus events.EventBus, prRepo pr_db.PrRepo, emailSenderService *EmailSenderService) *BatchActionService {
2728
return &BatchActionService{
28-
eventBus: eventBus,
29-
prRepo: prRepo,
30-
emailSenderService: emailSenderService,
29+
eventBus: eventBus,
30+
prRepo: prRepo,
31+
emailSenderService: emailSenderService,
32+
actionMappingService: prservice.ActionMappingService{SMService: &prservice.StateModelService{}},
3133
}
3234
}
35+
3336
func (s *BatchActionService) BatchAction(ctx common.ExtendedContext, event events.Event) {
3437
_, _ = s.eventBus.ProcessTask(ctx, event, events.SignalConsumers, s.batchAction)
3538
}
@@ -141,13 +144,17 @@ func (s *BatchActionService) RequestAging(ctx common.ExtendedContext, event even
141144
var processedCount = 0
142145
if len(prs) > 0 {
143146
for _, pr := range prs {
144-
var action = prservice.BorrowerActionCancelRequest
145-
if pr.Side == prservice.SideLending {
146-
action = prservice.LenderActionCannotSupply
147+
actionMapping, mappingErr := s.actionMappingService.GetActionMapping(pr.IllRequest)
148+
if mappingErr != nil {
149+
return events.NewErrorResult("could not find action mapping for patron request: "+pr.ID, mappingErr.Error())
150+
}
151+
action := actionMapping.GetClosingAction(pr)
152+
if action == nil {
153+
return events.NewErrorResult("could not find closing action for patron request state: "+string(pr.State)+" within state model: "+actionMapping.StateModelName, "closing action not found")
147154
}
148155
childBatchActionData := *batchActionData
149156
data := events.EventData{CommonEventData: events.CommonEventData{
150-
Action: &action,
157+
Action: action,
151158
BatchActionData: &childBatchActionData,
152159
}, CustomData: backgroundActionParams(event.EventData.CustomData)}
153160
_, eventErr := s.eventBus.CreateTask(pr.ID, events.EventNameInvokeBackgroundAction, data, events.EventDomainPatronRequest, &event.ID, events.SignalConsumers)

broker/scheduler/service/batch_action_test.go

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -323,10 +323,10 @@ func TestRequestAging_NoPatronRequestsReturnsSuccess(t *testing.T) {
323323
assert.Empty(t, eventBus.createTaskCalls)
324324
}
325325

326-
func TestRequestAging_CreatesBackgroundTasksForBorrowingAndLending(t *testing.T) {
326+
func TestRequestAging_CreatesBackgroundTasksForLending(t *testing.T) {
327327
repo := &mockEmailPrRepo{listResult: []pr_db.PatronRequest{
328-
{ID: "borrowing-1", Side: prservice.SideBorrowing},
329-
{ID: "lending-1", Side: prservice.SideLending},
328+
{ID: "lending-1", Side: prservice.SideLending, State: prservice.LenderStateValidated},
329+
{ID: "lending-2", Side: prservice.SideLending, State: prservice.LenderStateWillSupply},
330330
}}
331331
eventBus := &mockBatchActionEventBus{}
332332
svc := NewBatchActionService(eventBus, repo, nil)
@@ -337,8 +337,8 @@ func TestRequestAging_CreatesBackgroundTasksForBorrowingAndLending(t *testing.T)
337337
assert.NotNil(t, result)
338338
assert.Equal(t, "processed patron request count: 2", result.Note)
339339
if assert.Len(t, eventBus.createTaskCalls, 2) {
340-
assertRequestAgingCreateTask(t, eventBus.createTaskCalls[0], "borrowing-1", prservice.BorrowerActionCancelRequest)
341-
assertRequestAgingCreateTask(t, eventBus.createTaskCalls[1], "lending-1", prservice.LenderActionCannotSupply)
340+
assertRequestAgingCreateTask(t, eventBus.createTaskCalls[0], "lending-1", prservice.LenderActionCannotSupply)
341+
assertRequestAgingCreateTask(t, eventBus.createTaskCalls[1], "lending-2", prservice.LenderActionCannotSupply)
342342
for _, call := range eventBus.createTaskCalls {
343343
assert.Equal(t, "Closing stale request", call.data.CustomData["note"])
344344
assert.Equal(t, "Expired", call.data.CustomData["reasonUnfilled"])
@@ -348,10 +348,27 @@ func TestRequestAging_CreatesBackgroundTasksForBorrowingAndLending(t *testing.T)
348348
}
349349
}
350350

351+
func TestRequestAging_FailsIfNoClosingActionForState(t *testing.T) {
352+
repo := &mockEmailPrRepo{listResult: []pr_db.PatronRequest{
353+
{ID: "lending-1", Side: prservice.SideLending, State: prservice.LenderStateShipped},
354+
{ID: "lending-2", Side: prservice.SideLending, State: prservice.LenderStateWillSupply},
355+
}}
356+
eventBus := &mockBatchActionEventBus{}
357+
svc := NewBatchActionService(eventBus, repo, nil)
358+
359+
status, result := svc.RequestAging(testCtx, requestAgingEvent("cql.allRecords=1", map[string]any{"interval": "24h", "note": "Closing stale request", "reasonUnfilled": "Expired"}))
360+
361+
assert.Equal(t, events.EventStatusError, status)
362+
assert.NotNil(t, result)
363+
assert.Equal(t, "could not find closing action for patron request state: SHIPPED within state model: CrossLink Returnables State Model", result.EventError.Message)
364+
assert.Equal(t, "closing action not found", result.EventError.Cause)
365+
assert.Len(t, eventBus.createTaskCalls, 0)
366+
}
367+
351368
func TestRequestAging_CreateTaskErrorRecordsCustomDataAndContinues(t *testing.T) {
352369
repo := &mockEmailPrRepo{listResult: []pr_db.PatronRequest{
353-
{ID: "failed-1", Side: prservice.SideBorrowing},
354-
{ID: "ok-1", Side: prservice.SideBorrowing},
370+
{ID: "failed-1", Side: prservice.SideLending, State: prservice.LenderStateValidated},
371+
{ID: "ok-1", Side: prservice.SideLending, State: prservice.LenderStateWillSupply},
355372
}}
356373
eventBus := &mockBatchActionEventBus{createTaskErrByID: map[string]error{"failed-1": errors.New("create failed")}}
357374
svc := NewBatchActionService(eventBus, repo, nil)

misc/state-model.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@
9999
"type": "string",
100100
"description": "Indicates the primary action for the state, i.e., the most common or recommended action to be performed when in the state. The value must match the name of one of the actions defined for the state."
101101
},
102+
"closingAction": {
103+
"type": "string",
104+
"description": "Indicates the closing action for the state, i.e., the action to be performed when closing the state. The value must match the name of one of the actions defined for the state."
105+
},
102106
"editable": {
103107
"type": "boolean",
104108
"description": "Indicates that a patron request can be updated"

misc/state-models.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ stateModels:
338338
desc: Request is valid
339339
side: SUPPLIER
340340
primaryAction: will-supply
341+
closingAction: cannot-supply
341342
actions:
342343
- name: will-supply
343344
desc: Indicate supplier will supply and send ISO18626 WillSupply
@@ -373,6 +374,7 @@ stateModels:
373374
desc: After manual will-supply or successful auto-responder
374375
side: SUPPLIER
375376
primaryAction: ship
377+
closingAction: cannot-supply
376378
actions:
377379
- name: add-condition
378380
desc: Add conditions and notify requester
@@ -400,6 +402,7 @@ stateModels:
400402
desc: Conditions are sent with a special ISO WillSupply
401403
side: SUPPLIER
402404
primaryAction: cannot-supply
405+
closingAction: cannot-supply
403406
actions:
404407
- name: add-condition
405408
desc: Add additional conditions and notify requester
@@ -425,6 +428,7 @@ stateModels:
425428
desc: After receiving conditions accepted notification
426429
side: SUPPLIER
427430
primaryAction: ship
431+
closingAction: cannot-supply
428432
actions:
429433
- name: add-condition
430434
desc: Add additional conditions and notify requester

0 commit comments

Comments
 (0)