Automated Patron Blocks feature design

Purpose of this document

It needs to be decided which module "automated patron blocks" functionality has to be implemented in. There are few options:

  • mod-circulation (Approach 1)
  • new "automated blocks" module (mod-automated-blocks)

    • fetching data from mod-circulation (circular dependency)

    • fetching data from mod-circulation-storage

    • consuming events published by mod-circulation

      • mod-circulation requests block from mod-automated-blocks (Approach 2)
      • mod-automated-blocks publishes block events

Overview

It is required for a number of modules (both BE and FE) to be able to check if a patron should be blocked from borrowing, renewing and/or requesting items and why. mod-circulation should check for these blocks every time one of these actions is performed. Also, we need to provide an endpoint (at least for UI modules, see UIU-1273) for checking patron block conditions. Each of these condition checks has a dependency on functionality implemented in various modules:

ConditionModulePurpose

Maximum outstanding fee/fine balance

mod-feesfines

Calculate fee/fine balance

Maximum number of items charged out

mod-circulation

Get the number of open loans

Maximum number of lost items

mod-feesfines

Get a number of open fees/fines with item status "Aged to lost" or "Declared lost"

Maximum number of overdue item

mod-circulation

Get overdue period (CIRC-548)

Maximum number of overdue recalled items

mod-circulation

Get overdue period (CIRC-548)

Maximum number of overdue days for recalled item

mod-circulation

Get overdue period (CIRC-548)

Approach 1 (mod-circulation)

API

Even though most of the checks will be happening internally in mod-circulation, other modules (UIU-1273) will need to use this functionality to display existing patron blocks to the user, so it is proposed to add a new endpoint:

GET /automated-patron-blocks/{patronId}

Response example:

{
  "automatedPatronBlocks": [
    {
      "blockBorrowing": true,
      "blockRenewals": false,
      "blockRequests": false,
      "message": "Patron has reached maximum allowed number of items charged out"
    },
    {
      "blockBorrowing": false,
      "blockRenewals": false,
      "blockRequests": true,
      "message": "Patron has reached maximum allowed outstanding fee/fine balance for his/her patron group"
    }
  ]
}

Dependencies

No new dependencies are required in mod-circulation for Approach 1.

ModuleEndpointNew module dependencyPurpose

mod-circulation → mod-users

/patron-block-condition
/patron-block-limits?query=(patronGroupId=={patronGroupId})
No

Get conditions and limits to be checked.

mod-circulation → mod-feesfines

/accounts?query=(userId=={patronId} AND status=="Open")
No

Check outstanding fee/fine balance and number of open fees/fines for lost items.

mod-circulation → mod-calendar

/calendar/periods
No

Calculate the overdue period (already implemented in CIRC-548).

Approach 2 (new module; pub-sub)

New module (mod-automated-blocks) will be created. It will receive info about circulation events and fees/fines from event subscriptions.

Publishing/subscriptions configuration

Module

Publish/subscribe

Event type

Payload

mod-feesfines

publish

FEE_FINE_BALANCE_CHANGED

{
"feeFineId": string,
  "userId": string,
  "balance": numeric,
"feeFineTypeId": string
}

Example:
{
"feeFineId": "82d804b9-8a73-4d9d-bf9b-78f751758420",
  "userId": "4f0e711c-d583-41e0-9555-b62f1725023f",
  "balance": 15.45,
"feeFineTypeId": "95df458a-5a01-4f9a-99e1-64d5657d8379"
}
mod-circulationpublish

ITEM_CHECKED_OUT

{
  "userId": string,
  "loanId": string,
  "dueDate": string
}
mod-circulationpublishITEM_CHECKED_IN
{
  "userId": string,
"loanId": string,
"returnDate": string
}
mod-circulationpublishITEM_DECLARED_LOST
{
  "userId": string,
"loanId": string
}
mod-circulationpublishLOAN_DUE_DATE_CHANGED
{
  "userId": string,
  "loanId": string,
  "dueDate": string,
"dueDateChangedByRecall": boolean
}
mod-automatedblockssubscribe

FEE_FINE_BALANCE_CHANGED
ITEM_CHECKED_OUT
ITEM_CHECKED_IN
ITEM_DECLARED_LOST
LOAN_DUE_DATE_CHANGED


DB

Using the info from events mod-automated-blocks is subscribed to, we need to maintain one object per patron in the DB:

{
  "id": string,
  "userId": string,
  "outstandingFeeFineBalance": numeric,
  "numberOfLostItems": numeric,
  "openLoans": [
    {
      "loanId": string,
      "dueDate": string,
      "returnedDate": string,
      "recall": boolean
    }
  ],
  "openFeesFines": [
    {
      "feeFineId": string,
      "balance": numeric,
      "feeFineTypeId": string
    }
  ]
}

This object allows to check each of the block conditions for a patron:

ConditionCheck against

Maximum outstanding fee/fine balance

.outstandingFeeFineBalance

Maximum number of items charged out

number of .openLoans objects

Maximum number of lost items

.numberOfLostItems

Maximum number of overdue items

number of .openLoans[dueDate < returnedDate]

Maximum number of overdue recalled items

number of .openLoans[dueDate < returnedDate AND recall == true]

Maximum number of overdue days for recalled item

max of .openLoans[dueDate < returnedDate AND recall == true].(returnedDate - dueDate)

API

GET /automated-patron-blocks/{patronId}

Other modules will use this endpoint to determine if patron should be blocked from borrowing, renewing and/or requesting items and why.

Response example:

{
  "automatedPatronBlocks": [
    {
      "patronBlockConditionId": "2149fff5-a64c-4943-aa79-bb1d09511382",
      "blockBorrowing": true,
      "blockRenewals": false,
      "blockRequests": false,
      "message": "Patron has reached maximum allowed number of items charged out"
    },
    {
      "patronBlockConditionId": "ac13a725-b25f-48fa-84a6-4af021d13afe",
      "blockBorrowing": false,
      "blockRenewals": false,
      "blockRequests": true,
      "message": "Patron has reached maximum allowed outstanding fee/fine balance for his/her patron group"
    }
  ]
}

GET /patron-block-condition
GET /patron-block-conditions/{patronBlockConditionId}
PUT /patron-block-conditions/{patronBlockConditionId}
GET /patron-block-limits
POST /patron-block-limits
GET /patron-block-limits/{patronBlockLimitId}
PUT /patron-block-limits/{patronBlockLimitId}
DELETE /patron-block-limits/{patronBlockLimitId}

These endpoints will be moved from mod-users. This allows to avoid mod-automated-blocks dependency on mod-users.


Dependencies

ModuleEndpointPurpose
mod-circulation → mod-automated-blocks
GET /automated-patron-blocks/{patronId}
Check if action is allowed before borrowing, renewing and/or requesting items.

mod-automated-blocks → mod-users

GET /users/{id}
To determine which patron group a patron belongs to.