Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions broker/migrations/020_add_attention_field.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
DROP VIEW patron_request_search_view ;

ALTER TABLE patron_request DROP COLUMN needs_attention;

DROP INDEX IF EXISTS idx_pr_state;
DROP INDEX IF EXISTS idx_pr_side;
DROP INDEX IF EXISTS idx_pr_requester_symbol;
DROP INDEX IF EXISTS idx_pr_supplier_symbol;
DROP INDEX IF EXISTS idx_pr_requester_req_id;
DROP INDEX IF EXISTS idx_pr_needs_attention;
DROP INDEX IF EXISTS idx_pr_timestamp;

DROP INDEX IF EXISTS idx_pr_service_type;
DROP INDEX IF EXISTS idx_pr_service_level;
DROP INDEX IF EXISTS idx_pr_needed_at;

DROP INDEX IF EXISTS idx_notification_pr_id;
DROP INDEX IF EXISTS idx_notification_pr_id_has_cost;
DROP INDEX IF EXISTS idx_notification_pr_id_unread;

DROP FUNCTION IF EXISTS immutable_to_timestamp;
50 changes: 50 additions & 0 deletions broker/migrations/020_add_attention_field.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
ALTER TABLE patron_request ADD COLUMN needs_attention BOOLEAN NOT NULL DEFAULT false;

CREATE OR REPLACE FUNCTION immutable_to_timestamp(text)
RETURNS timestamp
LANGUAGE sql
IMMUTABLE STRICT
AS $$
SELECT $1::timestamp;
$$;

CREATE OR REPLACE VIEW patron_request_search_view AS
SELECT
pr.*,
EXISTS (
SELECT 1
FROM notification n
WHERE n.pr_id = pr.id
) AS has_notification,
EXISTS (
SELECT 1
FROM notification n
WHERE n.pr_id = pr.id and cost is not null
) AS has_cost,
EXISTS (
SELECT 1
FROM notification n
WHERE n.pr_id = pr.id and acknowledged_at is null
) AS has_unread_notification,
pr.ill_request -> 'serviceInfo' ->> 'serviceType' AS service_type,
pr.ill_request -> 'serviceInfo' -> 'serviceLevel' ->> '#text' AS service_level,
immutable_to_timestamp(pr.ill_request -> 'serviceInfo' ->> 'needBeforeDate') AS needed_at
FROM patron_request pr;

CREATE INDEX idx_pr_state ON patron_request (state);
CREATE INDEX idx_pr_side ON patron_request (side);
CREATE INDEX idx_pr_requester_symbol ON patron_request (requester_symbol);
CREATE INDEX idx_pr_supplier_symbol ON patron_request (supplier_symbol);
CREATE INDEX idx_pr_requester_req_id ON patron_request (requester_req_id);
CREATE INDEX idx_pr_needs_attention ON patron_request (needs_attention);
CREATE INDEX idx_pr_timestamp ON patron_request (timestamp);

CREATE INDEX idx_pr_service_type ON patron_request ((ill_request -> 'serviceInfo' ->> 'serviceType'));
CREATE INDEX idx_pr_service_level ON patron_request ((ill_request -> 'serviceInfo' -> 'serviceLevel' ->> '#text'));
CREATE INDEX idx_pr_needed_at ON patron_request (immutable_to_timestamp(ill_request -> 'serviceInfo' ->> 'needBeforeDate'));

CREATE INDEX idx_notification_pr_id ON notification (pr_id);
CREATE INDEX idx_notification_pr_id_has_cost ON notification (pr_id) WHERE cost IS NOT NULL;
CREATE INDEX idx_notification_pr_id_unread ON notification (pr_id) WHERE acknowledged_at IS NULL;


9 changes: 9 additions & 0 deletions broker/oapi/open-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,9 @@ components:
requesterRequestId:
type: string
description: Requester patron request ID
needsAttention:
type: boolean
description: Indicates if the request needs attention
lastAction:
type: string
description: Latest action on this request
Expand All @@ -480,6 +483,7 @@ components:
- state
- side
- illRequest
- needsAttention
PatronRequests:
type: object
required:
Expand Down Expand Up @@ -1121,6 +1125,11 @@ paths:
/patron_requests:
get:
summary: Retrieve patron requests
description: |
Use this endpoint to retrieve patron requests.
Query parameter cql can be used to filter the results.
With cql you can use these fields state, side, requester_symbol, supplier_symbol, needs_attention,
has_notification, has_cost, has_unread_notification, service_type, service_level, created_at, needed_at, requester_req_id.
tags:
- patron-requests-api
parameters:
Expand Down
1 change: 1 addition & 0 deletions broker/patron_request/api/api-handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,7 @@ func toApiPatronRequest(request pr_db.PatronRequest, illRequest iso18626.Request
SupplierSymbol: toString(request.SupplierSymbol),
IllRequest: utils.Must(common.StructToMap(illRequest)),
RequesterRequestId: toString(request.RequesterReqID),
NeedsAttention: request.NeedsAttention,
LastAction: toString(request.LastAction),
LastActionOutcome: toString(request.LastActionOutcome),
LastActionResult: toString(request.LastActionResult),
Expand Down
53 changes: 39 additions & 14 deletions broker/patron_request/db/prcql.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,30 @@ func handlePatronRequestsQuery(cqlString string, noBaseArgs int) (pgcql.Query, e
f = pgcql.NewFieldString().WithExact()
def.AddField("requester_req_id", f)

f = pgcql.NewFieldString().WithExact()
def.AddField("needs_attention", f)

fb := pgcql.NewFieldBool()
def.AddField("has_notification", fb)

fb = pgcql.NewFieldBool()
def.AddField("has_cost", fb)

fb = pgcql.NewFieldBool()
def.AddField("has_unread_notification", fb)

f = pgcql.NewFieldString().WithExact()
def.AddField("service_type", f)

f = pgcql.NewFieldString().WithExact()
def.AddField("service_level", f)

nf := pgcql.NewFieldDate().WithColumn("timestamp")
def.AddField("created_at", nf)

nf = pgcql.NewFieldDate()
def.AddField("needed_at", nf)

var parser cql.Parser
query, err := parser.Parse(cqlString)
if err != nil {
Expand All @@ -53,7 +77,7 @@ func (q *Queries) ListPatronRequestsCql(ctx context.Context, db DBTX, arg ListPa
if cqlString == nil {
return q.ListPatronRequests(ctx, db, arg)
}
noBaseArgs := 2 // weh have two base arguments: limit and offset
noBaseArgs := 2 // we have two base arguments: limit and offset
res, err := handlePatronRequestsQuery(*cqlString, noBaseArgs)
if err != nil {
return nil, err
Expand All @@ -80,19 +104,20 @@ func (q *Queries) ListPatronRequestsCql(ctx context.Context, db DBTX, arg ListPa
for rows.Next() {
var i ListPatronRequestsRow
if err := rows.Scan(
&i.PatronRequest.ID,
&i.PatronRequest.Timestamp,
&i.PatronRequest.IllRequest,
&i.PatronRequest.State,
&i.PatronRequest.Side,
&i.PatronRequest.Patron,
&i.PatronRequest.RequesterSymbol,
&i.PatronRequest.SupplierSymbol,
&i.PatronRequest.Tenant,
&i.PatronRequest.RequesterReqID,
&i.PatronRequest.LastAction,
&i.PatronRequest.LastActionOutcome,
&i.PatronRequest.LastActionResult,
&i.ID,
&i.Timestamp,
&i.IllRequest,
&i.State,
&i.Side,
&i.Patron,
&i.RequesterSymbol,
&i.SupplierSymbol,
&i.Tenant,
&i.RequesterReqID,
&i.NeedsAttention,
&i.LastAction,
&i.LastActionOutcome,
&i.LastActionResult,
&i.FullCount,
); err != nil {
return nil, err
Expand Down
23 changes: 22 additions & 1 deletion broker/patron_request/db/prrepo.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
type PrRepo interface {
repo.Transactional[PrRepo]
GetPatronRequestById(ctx common.ExtendedContext, id string) (PatronRequest, error)
GetPatronRequestByIdForUpdate(ctx common.ExtendedContext, id string) (PatronRequest, error)
GetPatronRequestByIdAndSide(ctx common.ExtendedContext, id string, side PatronRequestSide) (PatronRequest, error)
ListPatronRequests(ctx common.ExtendedContext, args ListPatronRequestsParams, cql *string) ([]PatronRequest, int64, error)
UpdatePatronRequest(ctx common.ExtendedContext, params UpdatePatronRequestParams) (PatronRequest, error)
Expand Down Expand Up @@ -49,6 +50,11 @@ func (r *PgPrRepo) GetPatronRequestById(ctx common.ExtendedContext, id string) (
return row.PatronRequest, err
}

func (r *PgPrRepo) GetPatronRequestByIdForUpdate(ctx common.ExtendedContext, id string) (PatronRequest, error) {
row, err := r.queries.GetPatronRequestByIdForUpdate(ctx, r.GetConnOrTx(), id)
return row.PatronRequest, err
}

func (r *PgPrRepo) GetPatronRequestByIdAndSide(ctx common.ExtendedContext, id string, side PatronRequestSide) (PatronRequest, error) {
pr, err := r.GetPatronRequestById(ctx, id)
if err != nil {
Expand All @@ -69,7 +75,22 @@ func (r *PgPrRepo) ListPatronRequests(ctx common.ExtendedContext, params ListPat
fullCount = rows[0].FullCount
for _, r := range rows {
fullCount = r.FullCount
list = append(list, r.PatronRequest)
list = append(list, PatronRequest{
ID: r.ID,
Timestamp: r.Timestamp,
IllRequest: r.IllRequest,
State: PatronRequestState(r.State),
Side: PatronRequestSide(r.Side),
Patron: r.Patron,
RequesterSymbol: r.RequesterSymbol,
SupplierSymbol: r.SupplierSymbol,
Tenant: r.Tenant,
RequesterReqID: r.RequesterReqID,
NeedsAttention: r.NeedsAttention,
LastAction: r.LastAction,
LastActionOutcome: r.LastActionOutcome,
LastActionResult: r.LastActionResult,
})
}
} else {
params.Limit = 1
Expand Down
25 changes: 25 additions & 0 deletions broker/patron_request/service/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ func (a *PatronRequestActionService) finalizeActionExecution(ctx common.Extended
updatedPr.LastAction = getDbText(string(action))
updatedPr.LastActionOutcome = getDbText(execResult.outcome)
updatedPr.LastActionResult = getDbText(string(execResult.status))
if execResult.outcome == ActionOutcomeFailure {
updatedPr.NeedsAttention = true
}
stateChanged := false
if transitionState, ok := actionMapping.GetActionTransition(currentPr, action, execResult.outcome); ok && transitionState != updatedPr.State {
updatedPr.State = transitionState
Expand All @@ -112,6 +115,9 @@ func (a *PatronRequestActionService) finalizeActionExecution(ctx common.Extended
if stateChanged {
err := a.RunAutoActionsOnStateEntry(ctx, updatedPr, &event.ID)
if err != nil {
if !updatedPr.NeedsAttention {
a.setNeedsAttention(ctx, updatedPr)
}
return events.LogErrorAndReturnResult(ctx, "failed to execute auto action", err)
}
}
Expand Down Expand Up @@ -721,6 +727,25 @@ func (a *PatronRequestActionService) checkSupplyingResponse(status events.EventS
return actionExecutionResult{status: events.EventStatusSuccess, result: nil, outcome: ActionOutcomeSuccess, pr: pr}
}

func (a *PatronRequestActionService) setNeedsAttention(ctx common.ExtendedContext, pr pr_db.PatronRequest) {
err := a.prRepo.WithTxFunc(ctx, func(repo pr_db.PrRepo) error {
prToUpdate, err := repo.GetPatronRequestByIdForUpdate(ctx, pr.ID)
if err != nil {
return err
}
if prToUpdate.NeedsAttention {
return nil
}
prToUpdate.NeedsAttention = true
_, err = repo.UpdatePatronRequest(ctx, pr_db.UpdatePatronRequestParams(prToUpdate))
return err
})
if err != nil {
ctx.Logger().Error("failed to set needs attention", "pr_id", pr.ID, "error", err)
return
}
}

type ResponseCaptureWriter struct {
IllMessage *iso18626.ISO18626Message
StatusCode int
Expand Down
Loading
Loading