Skip to content

Commit

Permalink
serials: manage serial claims
Browse files Browse the repository at this point in the history
Adds a daily job to:

1. Change the issue status to LATE for all expected
issues when the expected date is passed.

2. Change the issue status to CLAIMED for LATE issues
when the corresponding holdings record has a valid vendor
with an email address and max_number_of_claims is not reached.

2.1. Change the issue status to CLAIMED for all LATE
issues when the days_for_first_claim is passed.

2.2. Increment the claims_count field for all CLAIMED
issue if the days_for_next_claim passed.

The job is scheduled to run every midnight.

* Improves inheritance between the Item, ItemIssue classes.
* Closes rero#1437
* Closes rero#1435
* Create tests and fixtures accordingly.

Co-Authored-by: Aly Badr <aly.badr@rero.ch>
  • Loading branch information
Aly Badr authored and iGor milhit committed Nov 12, 2020
1 parent 8db7474 commit a17a0f5
Show file tree
Hide file tree
Showing 23 changed files with 551 additions and 135 deletions.
18 changes: 9 additions & 9 deletions data/patterns.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"patterns": {
"template": "no {{first_enumeration.level_1}} {{first_chronology.level_2}} {{first_chronology.level_1}}",
"frequency": "rdafr:1010",
"next_expected_date": "2020-03-01",
"next_expected_date": "2010-03-01",
"max_number_of_claims": 3,
"days_before_first_claim": 7,
"days_before_next_claim": 7,
Expand Down Expand Up @@ -60,7 +60,7 @@
"patterns": {
"template": "{{first_enumeration.level_1}} {{first_chronology.level_1}}",
"frequency": "rdafr:1013",
"next_expected_date": "2020-01-02",
"next_expected_date": "2010-01-02",
"max_number_of_claims": 3,
"days_before_first_claim": 7,
"days_before_next_claim": 7,
Expand Down Expand Up @@ -92,7 +92,7 @@
"patterns": {
"template": "{{first_enumeration.level_1}} Edition {{first_chronology.level_1}}",
"frequency": "rdafr:1013",
"next_expected_date": "2020-06-01",
"next_expected_date": "2010-06-01",
"max_number_of_claims": 3,
"days_before_first_claim": 7,
"days_before_next_claim": 7,
Expand Down Expand Up @@ -124,7 +124,7 @@
"patterns": {
"template": "Jg. {{first_enumeration.level_1}} {{first_chronology.level_2}} {{first_chronology.level_1}}",
"frequency": "rdafr:1014",
"next_expected_date": "2020-03-03",
"next_expected_date": "2010-03-03",
"max_number_of_claims": 3,
"days_before_first_claim": 7,
"days_before_next_claim": 7,
Expand Down Expand Up @@ -188,7 +188,7 @@
"patterns": {
"template": "Jg. {{first_enumeration.level_1}} Heft {{first_chronology.level_2}} {{first_chronology.level_1}}",
"frequency": "rdafr:1010",
"next_expected_date": "2020-09-01",
"next_expected_date": "2010-09-01",
"values": [
{
"name": "first_enumeration",
Expand Down Expand Up @@ -227,7 +227,7 @@
"patterns": {
"template": "ann\u00e9e {{first_chronology.level_1}} no {{first_enumeration.level_1}} {{second_chronology.level_2}} {{second_chronology.level_1}}",
"frequency": "rdafr:1010",
"next_expected_date": "2020-03-20",
"next_expected_date": "2010-03-20",
"max_number_of_claims": 3,
"days_before_first_claim": 7,
"days_before_next_claim": 7,
Expand Down Expand Up @@ -285,7 +285,7 @@
"patterns": {
"template": "N\u02da {{first_enumeration.level_1}} {{first_chronology.level_2}} {{first_chronology.level_1}}",
"frequency": "rdafr:1012",
"next_expected_date": "2020-03-20",
"next_expected_date": "2010-03-20",
"values": [
{
"name": "first_enumeration",
Expand Down Expand Up @@ -321,7 +321,7 @@
"patterns": {
"template": "{{first_enumeration.level_1}} {{first_chronology.level_2}} {{first_chronology.level_1}}",
"frequency": "rdafr:1007",
"next_expected_date": "2020-01-15",
"next_expected_date": "2010-01-15",
"max_number_of_claims": 3,
"days_before_first_claim": 7,
"days_before_next_claim": 7,
Expand Down Expand Up @@ -364,7 +364,7 @@
"patterns": {
"template": "Ann\u00e9e {{first_enumeration.level_1}} no {{second_enumeration.level_1}} {{first_chronology.level_2}} {{first_chronology.level_1}}",
"frequency": "rdafr:1012",
"next_expected_date": "2020-06-01",
"next_expected_date": "2010-06-01",
"max_number_of_claims": 3,
"days_before_first_claim": 7,
"days_before_next_claim": 7,
Expand Down
56 changes: 1 addition & 55 deletions data/vendors.json
Original file line number Diff line number Diff line change
Expand Up @@ -316,59 +316,5 @@
"organisation": {
"$ref": "https://ils.rero.ch/api/organisations/3"
}
},
{
"pid": "19",
"name": "Flourish and Blotts Bookseller",
"website": "http://www.flourishandblotts.com",
"communication_language": "eng",
"default_contact": {
"city": "London",
"email": "reroilstest+vendor7@gmail.com",
"phone": "+448444825000",
"street": "Diagon Alley",
"country": "UK"
},
"currency": "EUR",
"vat_rate": 20,
"organisation": {
"$ref": "https://ils.rero.ch/api/organisations/1"
}
},
{
"pid": "20",
"name": "Flourish and Blotts Bookseller",
"website": "http://www.flourishandblotts.com",
"communication_language": "eng",
"default_contact": {
"city": "London",
"email": "reroilstest+vendor7@gmail.com",
"phone": "+448444825000",
"street": "Diagon Alley",
"country": "UK"
},
"currency": "EUR",
"vat_rate": 20,
"organisation": {
"$ref": "https://ils.rero.ch/api/organisations/2"
}
},
{
"pid": "21",
"name": "Flourish and Blotts Bookseller",
"website": "http://www.flourishandblotts.com",
"communication_language": "eng",
"default_contact": {
"city": "London",
"email": "reroilstest+vendor7@gmail.com",
"phone": "+448444825000",
"street": "Diagon Alley",
"country": "UK"
},
"currency": "EUR",
"vat_rate": 20,
"organisation": {
"$ref": "https://ils.rero.ch/api/organisations/3"
}
}
]
]
28 changes: 25 additions & 3 deletions rero_ils/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
ItemOnLoanToItemInTransitHouse, ItemOnLoanToItemOnLoan, \
ItemOnLoanToItemReturned, PendingToItemAtDesk, \
PendingToItemInTransitPickup, ToCancelled, ToItemOnLoan
from invenio_records_rest.facets import terms_filter

from .modules.acq_accounts.api import AcqAccount
from .modules.acq_accounts.permissions import AcqAccountPermission
Expand All @@ -62,7 +63,7 @@
from .modules.item_types.api import ItemType
from .modules.item_types.permissions import ItemTypePermission
from .modules.items.api import Item
from .modules.items.models import ItemCirculationAction
from .modules.items.models import ItemCirculationAction, ItemIssueStatus
from .modules.items.permissions import ItemPermission
from .modules.items.utils import item_location_retriever
from .modules.libraries.api import Library
Expand Down Expand Up @@ -297,6 +298,12 @@ def _(x):
'enabled': False
# TODO: in production set this up once a day
},
'claims-creation': {
'task': ('rero_ils.modules.items.tasks'
'.process_late_claimed_issues'),
'schedule': crontab(minute=0, hour=6), # Every day at 06:00 UTC,
'enabled': False
},
'clear_and_renew_subscriptions': {
'task':
'rero_ils.modules.patrons.tasks.task_clear_and_renew_subscriptions',
Expand Down Expand Up @@ -1583,14 +1590,29 @@ def _(x):
terms=dict(
field='status',
size=RERO_ILS_DEFAULT_AGGREGATION_SIZE)
),
issue_status=dict(
terms=dict(
field='issue.status',
size=RERO_ILS_DEFAULT_AGGREGATION_SIZE,
include=[ItemIssueStatus.LATE, ItemIssueStatus.CLAIMED])
),
vendor=dict(
terms=dict(
field='vendor.pid',
size=RERO_ILS_DEFAULT_AGGREGATION_SIZE)
)
),
filters={
_('location'): and_term_filter('location.pid'),
_('library'): and_term_filter('library.pid'),
_('item_type'): and_term_filter('item_type.pid'),
_('status'): and_term_filter('status')
},
_('vendor'): and_term_filter('vendor.pid'),
_('issue_status'): and_term_filter('issue.status'),
# to allow multiple filters support, in this case to filter by
# "late or claimed"
'or_issue_status': terms_filter('issue.status')
}
),
patrons=dict(
aggs=dict(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
</a>
{%- endif %}
{%- for holding in holdings %}
{% set items = holding.get_items %}
{% set items = holding.get_items | sort(attribute='enumerationAndChronology', reverse=True) %}
{% set number_items = holding.get_items_count_by_holding_pid %}
{% if record.harvested or number_items >= 0 %}
<!-- Card header -->
Expand Down
28 changes: 28 additions & 0 deletions rero_ils/modules/holdings/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
from ..providers import Provider
from ..utils import extracted_data_from_ref, get_ref_for_pid, \
get_schema_for_resource
from ..vendors.api import Vendor

# holing provider
HoldingProvider = type(
Expand Down Expand Up @@ -225,6 +226,33 @@ def available(self):
items.append(Item.get_record_by_pid(item_pid))
return Holding.isAvailable(items)

@property
def max_number_of_claims(self):
"""Shortcut to return the max_number_of_claims."""
return self.get('patterns', {}).get('max_number_of_claims')

@property
def days_before_first_claim(self):
"""Shortcut to return the days_before_first_claim."""
return self.get('patterns', {}).get('days_before_first_claim')

@property
def days_before_next_claim(self):
"""Shortcut to return the days_before_next_claim."""
return self.get('patterns', {}).get('days_before_next_claim')

@property
def vendor_pid(self):
"""Shortcut for vendor pid of the holding."""
return self.replace_refs().get('vendor', {}).get('pid')

@property
def vendor(self):
"""Shortcut to return the vendor record."""
if self.vendor_pid:
return Vendor.get_record_by_pid(self.vendor_pid)
return None

@property
def notes(self):
"""Return notes related to this holding.
Expand Down
17 changes: 16 additions & 1 deletion rero_ils/modules/holdings/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,17 @@

import json
import random
from datetime import datetime, timedelta, timezone

import click
from flask.cli import with_appcontext

from ..documents.api import Document, DocumentsSearch
from ..holdings.api import Holding, create_holding
from ..item_types.api import ItemTypesSearch
from ..items.api import Item
from ..items.models import ItemIssueStatus
from ..items.tasks import process_late_claimed_issues
from ..locations.api import LocationsSearch
from ..organisations.api import Organisation
from ..utils import read_json_record
Expand Down Expand Up @@ -76,7 +80,8 @@ def get_random_vendor(org_pid):
"""Return random vendor for an organisation pid."""
org = Organisation.get_record_by_pid(org_pid)
vendors = [vendor.pid for vendor in org.get_vendors()]
return next(iter(random.choices(vendors) or []), None)
if vendors:
return next(iter(random.choices(vendors) or []), None)


def create_issues_from_holding(holding, min=3, max=9):
Expand Down Expand Up @@ -168,3 +173,13 @@ def create_patterns(infile, verbose, debug, lazy):
document=document_pid
))
record_index = record_index + 1
# create some late issues.
process_late_claimed_issues(dbcommit=True, reindex=True)
# make late issues ready for a claim
for item in Item.get_issues_by_status(issue_status=ItemIssueStatus.LATE):
holding = Holding.get_record_by_pid(item.holding_pid)
item['issue']['status_date'] = \
(datetime.now(timezone.utc) - timedelta(days=8)).isoformat()
item.update(item, dbcommit=True, reindex=True)
# create claims
process_late_claimed_issues(dbcommit=True, reindex=True)
16 changes: 14 additions & 2 deletions rero_ils/modules/holdings/jsonschemas/holdings/holding-v0.0.1.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"circulation_category",
"location",
"holdings_type",
"vendor",
"enumerationAndChronology",
"supplementaryContent",
"index",
Expand Down Expand Up @@ -142,6 +143,9 @@
"frequency"
],
"propertiesOrder": [
"max_number_of_claims",
"days_before_first_claim",
"days_before_next_claim",
"template",
"frequency",
"next_expected_date",
Expand Down Expand Up @@ -449,11 +453,19 @@
"vendor": {
"title": "Vendor",
"type": "object",
"required": [
"$ref"
],
"properties": {
"$ref": {
"title": "Vendor URI",
"type": "string",
"pattern": "^https://ils.rero.ch/api/vendors/.*?$"
"pattern": "^https://ils.rero.ch/api/vendors/.*?$",
"form": {
"remoteOptions": {
"type": "vendors"
}
}
}
}
},
Expand Down Expand Up @@ -585,4 +597,4 @@
}
}
}
}
}
3 changes: 1 addition & 2 deletions rero_ils/modules/items/api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@

from .circulation import ItemCirculation
from .issue import ItemIssue
from .record import ItemRecord
from ..models import ItemIdentifier, ItemMetadata
from ..utils import item_pid_to_object
from ...api import IlsRecordError, IlsRecordsIndexer, IlsRecordsSearch
Expand Down Expand Up @@ -88,7 +87,7 @@ def flush(cls):
current_search.flush_and_refresh(cls.Meta.index)


class Item(ItemRecord, ItemCirculation, ItemIssue):
class Item(ItemCirculation, ItemIssue):
"""Item class."""

minter = item_id_minter
Expand Down
4 changes: 2 additions & 2 deletions rero_ils/modules/items/api/circulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@
from invenio_records_rest.utils import obj_or_import_string
from invenio_search import current_search

from .record import ItemRecord
from ..decorators import add_action_parameters_and_flush_indexes, \
check_operation_allowed
from ..models import ItemCirculationAction, ItemStatus
from ..utils import item_pid_to_object
from ...api import IlsRecord
from ...circ_policies.api import CircPolicy
from ...documents.api import Document
from ...errors import NoCirculationAction
Expand All @@ -48,7 +48,7 @@
from ....filter import format_date_filter


class ItemCirculation(IlsRecord):
class ItemCirculation(ItemRecord):
"""Item circulation class."""

statuses = {
Expand Down
Loading

0 comments on commit a17a0f5

Please sign in to comment.