-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathholdings_builder.py
More file actions
142 lines (113 loc) · 4.4 KB
/
Copy pathholdings_builder.py
File metadata and controls
142 lines (113 loc) · 4.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
"""
Build a FOLIO holdings record dict from a group of 856 fields and a CollectionRow.
Multiple 856 fields sharing the same coral ID produce a single holdings record
with one electronicAccess entry per $u URI.
"""
import logging
import os
from folio_setup import (
NOTE_CORAL_ID,
NOTE_PACKAGE_NAME,
NOTE_PROVIDER,
NOTE_PROVIDER_CODE,
NOTE_ACCESS_METHOD,
NOTE_ACCESS_METHOD_CODE,
)
from srs_utils import get_subfield, get_all_subfields
log = logging.getLogger(__name__)
def build_holdings_record(instance_id, coral_id, fields_856, collection_row, ref_data):
"""
Return a holdings record dict ready for POST /holdings-storage/holdings.
instance_id -- FOLIO instance UUID
coral_id -- the 856$w value (e.g. "coral-160")
fields_856 -- list of parsed MARC 856 field dicts sharing this coral_id
collection_row -- CollectionRow from csv_lookup
ref_data -- UUID map from folio_setup.load_ref_data()
"""
notes = _build_notes(coral_id, collection_row, ref_data)
electronic_access = _build_electronic_access(fields_856, ref_data)
ill_policy_id = _resolve_ill_policy(collection_row.ill_policy, ref_data)
record = {
"instanceId": instance_id,
"holdingsTypeId": ref_data["holdings_type_electronic"],
"permanentLocationId": ref_data["location_electronic"],
"callNumberTypeId": ref_data["call_number_type_other"],
"callNumber": collection_row.call_number,
"copyNumber": collection_row.copy_number,
"sourceId": ref_data["holdings_source_folio"],
"discoverySuppress": False,
"notes": notes,
"electronicAccess": electronic_access,
}
if ill_policy_id:
record["illPolicyId"] = ill_policy_id
return record
def _build_notes(coral_id, row, ref_data):
note_types = ref_data["holdings_note_types"]
notes = []
_add_note(notes, note_types, NOTE_CORAL_ID, coral_id)
_add_note(notes, note_types, NOTE_PACKAGE_NAME, row.package_name)
_add_note(notes, note_types, NOTE_PROVIDER, row.provider_name)
_add_note(notes, note_types, NOTE_PROVIDER_CODE, row.provider_code)
if row.is_ebook:
if row.access_method:
_add_note(notes, note_types, NOTE_ACCESS_METHOD, row.access_method)
if row.access_method_code:
_add_note(
notes, note_types, NOTE_ACCESS_METHOD_CODE, row.access_method_code
)
return notes
def _add_note(notes, note_types, type_name, value):
if not value:
return
note_type_id = note_types.get(type_name)
if note_type_id is None:
raise ValueError(
f"Holdings note type not found in FOLIO: {type_name!r}. "
"Create it in Settings > Inventory > Holdings note types."
)
notes.append(
{
"holdingsNoteTypeId": note_type_id,
"note": value,
"staffOnly": False,
}
)
_INCLUDE_PUBLIC_NOTE = (
os.environ.get("INCLUDE_856_PUBLIC_NOTE", "true").lower() == "true"
)
def _build_electronic_access(fields_856, ref_data):
"""One electronicAccess entry per 856 $u, across all fields in the group."""
relationship_id = ref_data["ea_relationship_resource"]
ea_list = []
for f856 in fields_856:
uris = get_all_subfields(f856, "u")
z_value = get_subfield(f856, "z") or ""
public_note = z_value if _INCLUDE_PUBLIC_NOTE else ""
materials_specification = _extract_materials_specification(z_value)
for uri in uris:
entry = {
"uri": uri,
"relationshipId": relationship_id,
}
if public_note:
entry["publicNote"] = public_note
if materials_specification:
entry["materialsSpecification"] = materials_specification
ea_list.append(entry)
return ea_list
def _extract_materials_specification(z_value):
"""Return the portion of an 856 $z preceding ', Available', or None.
Fields whose $z starts with 'MARCIVE' never get a materialsSpecification value.
"""
if not z_value or z_value.startswith("MARCIVE"):
return None
prefix, sep, _ = z_value.partition(", Available")
if not sep:
return None
prefix = prefix.strip()
return prefix or None
def _resolve_ill_policy(policy_name, ref_data):
if not policy_name:
return None
return ref_data["ill_policies"].get(policy_name)