invenio-app-ils 1.0.0a54__py2.py3-none-any.whl → 6.1.0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (331) hide show
  1. invenio_app_ils/__init__.py +2 -2
  2. invenio_app_ils/acquisition/api.py +3 -1
  3. invenio_app_ils/acquisition/config.py +10 -21
  4. invenio_app_ils/acquisition/jsonresolvers/order_order_lines.py +1 -0
  5. invenio_app_ils/acquisition/mappings/os-v1/acq_orders/order-v1.0.0.json +364 -0
  6. invenio_app_ils/acquisition/mappings/os-v2/__init__.py +0 -0
  7. invenio_app_ils/acquisition/mappings/os-v2/acq_orders/order-v1.0.0.json +364 -0
  8. invenio_app_ils/acquisition/mappings/v7/acq_orders/order-v1.0.0.json +14 -0
  9. invenio_app_ils/acquisition/search.py +5 -15
  10. invenio_app_ils/assets/semantic-ui/less/theme.config +103 -0
  11. invenio_app_ils/assets/semantic-ui/templates/.gitkeep +0 -0
  12. invenio_app_ils/circulation/api.py +153 -67
  13. invenio_app_ils/circulation/config.py +29 -25
  14. invenio_app_ils/circulation/indexer.py +14 -19
  15. invenio_app_ils/circulation/loaders/__init__.py +2 -0
  16. invenio_app_ils/circulation/loaders/schemas/json/loan_checkout.py +2 -3
  17. invenio_app_ils/circulation/loaders/schemas/json/loan_request.py +82 -16
  18. invenio_app_ils/circulation/loaders/schemas/json/loan_self_checkout.py +19 -0
  19. invenio_app_ils/circulation/notifications/api.py +23 -19
  20. invenio_app_ils/circulation/notifications/messages.py +6 -6
  21. invenio_app_ils/circulation/notifications/tasks.py +1 -2
  22. invenio_app_ils/circulation/receivers.py +2 -5
  23. invenio_app_ils/circulation/search.py +23 -22
  24. invenio_app_ils/circulation/serializers/__init__.py +2 -2
  25. invenio_app_ils/circulation/serializers/csv.py +1 -3
  26. invenio_app_ils/circulation/serializers/custom_fields.py +5 -9
  27. invenio_app_ils/circulation/serializers/json.py +2 -6
  28. invenio_app_ils/circulation/serializers/response.py +12 -12
  29. invenio_app_ils/circulation/stats/views.py +5 -15
  30. invenio_app_ils/circulation/tasks.py +2 -6
  31. invenio_app_ils/circulation/templates/invenio_app_ils_circulation/notifications/self_checkout.html +19 -0
  32. invenio_app_ils/circulation/templates/invenio_app_ils_circulation/notifications/update_dates.html +19 -0
  33. invenio_app_ils/circulation/utils.py +23 -17
  34. invenio_app_ils/circulation/views.py +103 -39
  35. invenio_app_ils/cli.py +220 -260
  36. invenio_app_ils/closures/api.py +72 -7
  37. invenio_app_ils/closures/serializers/__init__.py +16 -0
  38. invenio_app_ils/closures/serializers/response.py +35 -0
  39. invenio_app_ils/closures/serializers/schema.py +28 -0
  40. invenio_app_ils/closures/tasks.py +4 -11
  41. invenio_app_ils/closures/views.py +66 -0
  42. invenio_app_ils/config.py +207 -150
  43. invenio_app_ils/document_requests/api.py +6 -21
  44. invenio_app_ils/document_requests/loaders/__init__.py +4 -12
  45. invenio_app_ils/document_requests/mappings/{v6 → os-v1}/__init__.py +2 -2
  46. invenio_app_ils/document_requests/mappings/os-v1/document_requests/document_request-v1.0.0.json +196 -0
  47. invenio_app_ils/document_requests/mappings/os-v2/__init__.py +8 -0
  48. invenio_app_ils/document_requests/mappings/os-v2/document_requests/document_request-v1.0.0.json +196 -0
  49. invenio_app_ils/document_requests/notifications/api.py +2 -7
  50. invenio_app_ils/document_requests/notifications/messages.py +3 -7
  51. invenio_app_ils/document_requests/search.py +2 -6
  52. invenio_app_ils/document_requests/views.py +4 -10
  53. invenio_app_ils/documents/api.py +19 -25
  54. invenio_app_ils/documents/indexer.py +13 -20
  55. invenio_app_ils/documents/jsonresolvers/document_circulation.py +11 -33
  56. invenio_app_ils/documents/jsonresolvers/document_eitem.py +1 -0
  57. invenio_app_ils/documents/jsonresolvers/document_item.py +8 -9
  58. invenio_app_ils/documents/jsonresolvers/document_stock.py +7 -7
  59. invenio_app_ils/documents/loaders/jsonschemas/document.py +3 -14
  60. invenio_app_ils/documents/mappings/{v6 → os-v1}/__init__.py +1 -1
  61. invenio_app_ils/documents/mappings/os-v1/documents/document-v1.0.0.json +932 -0
  62. invenio_app_ils/documents/mappings/os-v1/documents/document-v2.0.0.json +1066 -0
  63. invenio_app_ils/documents/mappings/os-v2/__init__.py +8 -0
  64. invenio_app_ils/documents/mappings/os-v2/documents/document-v1.0.0.json +932 -0
  65. invenio_app_ils/documents/mappings/os-v2/documents/document-v2.0.0.json +1066 -0
  66. invenio_app_ils/documents/mappings/v7/documents/document-v1.0.0.json +102 -11
  67. invenio_app_ils/documents/mappings/v7/documents/document-v2.0.0.json +1066 -0
  68. invenio_app_ils/documents/schemas/documents/document-v2.0.0.json +732 -0
  69. invenio_app_ils/eitems/api.py +41 -7
  70. invenio_app_ils/eitems/loaders/jsonschemas/eitems.py +6 -6
  71. invenio_app_ils/eitems/mappings/{v6 → os-v1}/__init__.py +1 -1
  72. invenio_app_ils/eitems/mappings/os-v1/eitems/eitem-v1.0.0.json +139 -0
  73. invenio_app_ils/eitems/mappings/os-v1/eitems/eitem-v2.0.0.json +142 -0
  74. invenio_app_ils/eitems/mappings/os-v1/eitems/eitem-v3.0.0.json +179 -0
  75. invenio_app_ils/{series/mappings/v6 → eitems/mappings/os-v2}/__init__.py +1 -1
  76. invenio_app_ils/eitems/mappings/os-v2/eitems/eitem-v1.0.0.json +139 -0
  77. invenio_app_ils/eitems/mappings/os-v2/eitems/eitem-v2.0.0.json +142 -0
  78. invenio_app_ils/eitems/mappings/os-v2/eitems/eitem-v3.0.0.json +179 -0
  79. invenio_app_ils/eitems/mappings/v7/eitems/eitem-v1.0.0.json +12 -2
  80. invenio_app_ils/eitems/mappings/v7/eitems/eitem-v2.0.0.json +142 -0
  81. invenio_app_ils/eitems/mappings/v7/eitems/eitem-v3.0.0.json +179 -0
  82. invenio_app_ils/eitems/schemas/eitems/eitem-v2.0.0.json +120 -0
  83. invenio_app_ils/eitems/schemas/eitems/eitem-v3.0.0.json +120 -0
  84. invenio_app_ils/eitems/search.py +3 -9
  85. invenio_app_ils/errors.py +119 -6
  86. invenio_app_ils/ext.py +15 -18
  87. invenio_app_ils/facets.py +13 -15
  88. invenio_app_ils/files/receivers.py +1 -1
  89. invenio_app_ils/files/views.py +1 -2
  90. invenio_app_ils/ill/api.py +1 -2
  91. invenio_app_ils/ill/config.py +10 -16
  92. invenio_app_ils/ill/jsonresolvers/borrowing_request_document.py +2 -3
  93. invenio_app_ils/ill/jsonresolvers/borrowing_request_patron.py +1 -3
  94. invenio_app_ils/ill/jsonresolvers/borrowing_request_provider.py +1 -3
  95. invenio_app_ils/ill/loaders/__init__.py +3 -9
  96. invenio_app_ils/ill/loaders/jsonschemas/patron_loan_actions.py +1 -8
  97. invenio_app_ils/ill/loaders/jsonschemas/patron_loan_extension_actions.py +3 -8
  98. invenio_app_ils/ill/mappings/{v6 → os-v1}/__init__.py +1 -1
  99. invenio_app_ils/ill/mappings/os-v1/ill_borrowing_requests/borrowing_request-v1.0.0.json +254 -0
  100. invenio_app_ils/{acquisition/mappings/v6 → ill/mappings/os-v2}/__init__.py +1 -1
  101. invenio_app_ils/ill/mappings/os-v2/ill_borrowing_requests/borrowing_request-v1.0.0.json +254 -0
  102. invenio_app_ils/ill/mappings/v7/ill_borrowing_requests/borrowing_request-v1.0.0.json +14 -0
  103. invenio_app_ils/ill/notifications/api.py +1 -4
  104. invenio_app_ils/ill/search.py +3 -9
  105. invenio_app_ils/ill/serializers/__init__.py +1 -3
  106. invenio_app_ils/ill/views.py +2 -4
  107. invenio_app_ils/internal_locations/api.py +1 -4
  108. invenio_app_ils/internal_locations/mappings/{v6 → os-v1}/__init__.py +1 -1
  109. invenio_app_ils/internal_locations/mappings/os-v1/internal_locations/internal_location-v1.0.0.json +108 -0
  110. invenio_app_ils/internal_locations/mappings/os-v2/__init__.py +8 -0
  111. invenio_app_ils/internal_locations/mappings/os-v2/internal_locations/internal_location-v1.0.0.json +108 -0
  112. invenio_app_ils/internal_locations/search.py +1 -3
  113. invenio_app_ils/items/api.py +18 -15
  114. invenio_app_ils/items/indexer.py +1 -3
  115. invenio_app_ils/items/jsonresolvers/item_document.py +1 -1
  116. invenio_app_ils/items/jsonresolvers/item_internal_location.py +2 -6
  117. invenio_app_ils/items/loaders/jsonschemas/items.py +2 -0
  118. {tests/api/circulation → invenio_app_ils/items/mappings/os-v1}/__init__.py +1 -1
  119. invenio_app_ils/items/mappings/os-v1/items/item-v1.0.0.json +285 -0
  120. invenio_app_ils/items/mappings/os-v1/items/item-v2.0.0.json +326 -0
  121. {tests/api/ill → invenio_app_ils/items/mappings/os-v2}/__init__.py +1 -1
  122. invenio_app_ils/items/mappings/os-v2/items/item-v1.0.0.json +285 -0
  123. invenio_app_ils/items/mappings/os-v2/items/item-v2.0.0.json +326 -0
  124. invenio_app_ils/items/mappings/v7/items/item-v1.0.0.json +11 -0
  125. invenio_app_ils/items/mappings/v7/items/item-v2.0.0.json +326 -0
  126. invenio_app_ils/items/schemas/items/item-v1.0.0.json +22 -0
  127. invenio_app_ils/items/schemas/items/item-v2.0.0.json +172 -0
  128. invenio_app_ils/items/search.py +18 -11
  129. invenio_app_ils/items/serializers/item.py +7 -6
  130. invenio_app_ils/literature/api.py +1 -3
  131. invenio_app_ils/literature/search.py +3 -5
  132. invenio_app_ils/literature/serializers/csv.py +1 -3
  133. invenio_app_ils/literature/serializers/json.py +1 -3
  134. invenio_app_ils/locations/api.py +2 -4
  135. invenio_app_ils/locations/indexer.py +3 -9
  136. invenio_app_ils/locations/loaders/__init__.py +1 -3
  137. invenio_app_ils/locations/loaders/jsonschemas/location.py +4 -11
  138. invenio_app_ils/locations/mappings/{v6 → os-v1}/__init__.py +1 -1
  139. invenio_app_ils/locations/mappings/os-v1/locations/location-v1.0.0.json +90 -0
  140. invenio_app_ils/locations/mappings/os-v2/__init__.py +8 -0
  141. invenio_app_ils/locations/mappings/os-v2/locations/location-v1.0.0.json +90 -0
  142. invenio_app_ils/notifications/messages.py +4 -3
  143. invenio_app_ils/notifications/tasks.py +1 -3
  144. invenio_app_ils/notifications/views.py +2 -2
  145. invenio_app_ils/patrons/anonymization.py +53 -32
  146. invenio_app_ils/patrons/api.py +3 -5
  147. invenio_app_ils/patrons/cli.py +1 -2
  148. invenio_app_ils/patrons/indexer.py +4 -13
  149. invenio_app_ils/patrons/mappings/os-v1/__init__.py +8 -0
  150. invenio_app_ils/patrons/mappings/os-v1/patrons/patron-v1.0.0.json +42 -0
  151. invenio_app_ils/patrons/mappings/os-v2/__init__.py +8 -0
  152. invenio_app_ils/patrons/mappings/os-v2/patrons/patron-v1.0.0.json +42 -0
  153. invenio_app_ils/patrons/views.py +4 -14
  154. invenio_app_ils/permissions.py +93 -35
  155. invenio_app_ils/providers/api.py +2 -6
  156. invenio_app_ils/providers/config.py +11 -19
  157. invenio_app_ils/providers/indexer.py +2 -6
  158. invenio_app_ils/providers/mappings/{v6 → os-v1}/__init__.py +1 -1
  159. invenio_app_ils/providers/mappings/os-v1/providers/provider-v1.0.0.json +57 -0
  160. invenio_app_ils/providers/mappings/os-v2/__init__.py +8 -0
  161. invenio_app_ils/providers/mappings/os-v2/providers/provider-v1.0.0.json +57 -0
  162. invenio_app_ils/providers/mappings/v7/__init__.py +1 -1
  163. invenio_app_ils/providers/proxies.py +1 -3
  164. invenio_app_ils/records/api.py +3 -9
  165. invenio_app_ils/records/loaders/schemas/changed_by.py +1 -3
  166. invenio_app_ils/records/loaders/schemas/identifiers.py +23 -0
  167. invenio_app_ils/records/metadata_extensions.py +1 -4
  168. invenio_app_ils/records/permissions.py +8 -2
  169. invenio_app_ils/records/serializers/__init__.py +1 -4
  170. invenio_app_ils/records/views.py +4 -7
  171. invenio_app_ils/records_relations/api.py +11 -34
  172. invenio_app_ils/records_relations/indexer.py +1 -3
  173. invenio_app_ils/records_relations/retriever.py +14 -9
  174. invenio_app_ils/records_relations/views.py +16 -50
  175. invenio_app_ils/relations/api.py +17 -16
  176. invenio_app_ils/search_permissions.py +24 -24
  177. invenio_app_ils/series/api.py +10 -12
  178. invenio_app_ils/series/loaders/jsonschemas/series.py +3 -2
  179. invenio_app_ils/{items/mappings/v6 → series/mappings/os-v1}/__init__.py +1 -1
  180. invenio_app_ils/series/mappings/os-v1/series/series-v1.0.0.json +324 -0
  181. invenio_app_ils/series/mappings/os-v1/series/series-v2.0.0.json +396 -0
  182. {tests/api/acquisition → invenio_app_ils/series/mappings/os-v2}/__init__.py +1 -1
  183. invenio_app_ils/series/mappings/os-v2/series/series-v1.0.0.json +324 -0
  184. invenio_app_ils/series/mappings/os-v2/series/series-v2.0.0.json +396 -0
  185. invenio_app_ils/series/mappings/v7/series/series-v1.0.0.json +35 -3
  186. invenio_app_ils/series/mappings/v7/series/series-v2.0.0.json +396 -0
  187. invenio_app_ils/series/schemas/series/series-v2.0.0.json +354 -0
  188. invenio_app_ils/stats/aggregations/aggr_file_download/os-v1/aggr-file-download-v1.json +60 -0
  189. invenio_app_ils/stats/aggregations/aggr_file_download/os-v2/__init__.py +9 -0
  190. invenio_app_ils/stats/aggregations/aggr_file_download/os-v2/aggr-file-download-v1.json +60 -0
  191. invenio_app_ils/stats/event_builders.py +73 -0
  192. invenio_app_ils/stats/file_download/os-v1/file-download-v1.json +72 -0
  193. invenio_app_ils/stats/file_download/os-v2/__init__.py +9 -0
  194. invenio_app_ils/stats/file_download/os-v2/file-download-v1.json +72 -0
  195. invenio_app_ils/stats/processors.py +30 -0
  196. invenio_app_ils/stats/templates/aggregations/__init__.py +8 -0
  197. invenio_app_ils/stats/templates/aggregations/ils_record_changes/__init__.py +8 -0
  198. invenio_app_ils/stats/templates/aggregations/ils_record_changes/os-v2/__init__.py +8 -0
  199. invenio_app_ils/stats/templates/aggregations/ils_record_changes/os-v2/aggr-ils-record-changes-v1.json +41 -0
  200. {tests → invenio_app_ils/stats/templates/events}/__init__.py +2 -2
  201. invenio_app_ils/stats/templates/events/ils_record_changes/__init__.py +8 -0
  202. invenio_app_ils/stats/templates/events/ils_record_changes/os-v2/__init__.py +8 -0
  203. invenio_app_ils/stats/templates/events/ils_record_changes/os-v2/ils-record-changes-v1.json +41 -0
  204. invenio_app_ils/templates/logged_out.html +12 -0
  205. invenio_app_ils/views.py +18 -4
  206. invenio_app_ils/vocabularies/api.py +1 -1
  207. invenio_app_ils/vocabularies/cli.py +6 -18
  208. invenio_app_ils/vocabularies/data/acq_order_line_payment_modes.json +5 -0
  209. invenio_app_ils/vocabularies/data/identifier_schemes.json +5 -0
  210. invenio_app_ils/vocabularies/indexer.py +1 -4
  211. invenio_app_ils/vocabularies/jsonresolvers/licenses.py +2 -11
  212. invenio_app_ils/vocabularies/mappings/os-v1/__init__.py +8 -0
  213. invenio_app_ils/vocabularies/mappings/os-v1/vocabularies/vocabulary-v1.0.0.json +23 -0
  214. invenio_app_ils/vocabularies/mappings/os-v2/__init__.py +8 -0
  215. invenio_app_ils/vocabularies/mappings/os-v2/vocabularies/vocabulary-v1.0.0.json +23 -0
  216. invenio_app_ils/vocabularies/sources/base.py +1 -3
  217. invenio_app_ils/webpack.py +27 -0
  218. invenio_app_ils-6.1.0.dist-info/METADATA +627 -0
  219. {invenio_app_ils-1.0.0a54.dist-info → invenio_app_ils-6.1.0.dist-info}/RECORD +227 -249
  220. {invenio_app_ils-1.0.0a54.dist-info → invenio_app_ils-6.1.0.dist-info}/WHEEL +1 -1
  221. {invenio_app_ils-1.0.0a54.dist-info → invenio_app_ils-6.1.0.dist-info}/entry_points.txt +9 -5
  222. {invenio_app_ils-1.0.0a54.dist-info → invenio_app_ils-6.1.0.dist-info}/top_level.txt +0 -1
  223. invenio_app_ils/acquisition/mappings/v6/acq_orders/order-v1.0.0.json +0 -352
  224. invenio_app_ils/document_requests/mappings/v6/document_requests/document_request-v1.0.0.json +0 -199
  225. invenio_app_ils/documents/mappings/v6/documents/document-v1.0.0.json +0 -843
  226. invenio_app_ils/eitems/mappings/v6/eitems/eitem-v1.0.0.json +0 -131
  227. invenio_app_ils/ill/mappings/v6/ill_borrowing_requests/borrowing_request-v1.0.0.json +0 -242
  228. invenio_app_ils/internal_locations/mappings/v6/internal_locations/internal_location-v1.0.0.json +0 -110
  229. invenio_app_ils/items/mappings/v6/items/item-v1.0.0.json +0 -276
  230. invenio_app_ils/locations/mappings/v6/locations/location-v1.0.0.json +0 -92
  231. invenio_app_ils/notifications/admin.py +0 -57
  232. invenio_app_ils/patrons/mappings/v6/__init__.py +0 -8
  233. invenio_app_ils/patrons/mappings/v6/patrons/patron-v1.0.0.json +0 -44
  234. invenio_app_ils/providers/mappings/v6/providers/provider-v1.0.0.json +0 -59
  235. invenio_app_ils/series/mappings/v6/series/series-v1.0.0.json +0 -298
  236. invenio_app_ils/stats/aggregations/aggr_file_download/v6/aggr-file-download-v1.json +0 -59
  237. invenio_app_ils/stats/file_download/v6/file-download-v1.json +0 -74
  238. invenio_app_ils/version.py +0 -14
  239. invenio_app_ils/vocabularies/mappings/v6/__init__.py +0 -8
  240. invenio_app_ils/vocabularies/mappings/v6/vocabularies/vocabulary-v1.0.0.json +0 -25
  241. invenio_app_ils-1.0.0a54.dist-info/METADATA +0 -95
  242. tests/api/__init__.py +0 -8
  243. tests/api/acquisition/test_acq_orders_crud.py +0 -102
  244. tests/api/acquisition/test_acq_orders_permissions.py +0 -104
  245. tests/api/acquisition/test_acq_providers_permissions.py +0 -83
  246. tests/api/circulation/test_expired_loans.py +0 -88
  247. tests/api/circulation/test_loan_checkout.py +0 -216
  248. tests/api/circulation/test_loan_default_durations.py +0 -57
  249. tests/api/circulation/test_loan_document_resolver.py +0 -18
  250. tests/api/circulation/test_loan_extend.py +0 -132
  251. tests/api/circulation/test_loan_item_permissions.py +0 -139
  252. tests/api/circulation/test_loan_item_resolver.py +0 -26
  253. tests/api/circulation/test_loan_list_permissions.py +0 -104
  254. tests/api/circulation/test_loan_patron_resolver.py +0 -38
  255. tests/api/circulation/test_loan_request.py +0 -234
  256. tests/api/circulation/test_loan_update.py +0 -150
  257. tests/api/circulation/test_notifications.py +0 -229
  258. tests/api/conftest.py +0 -236
  259. tests/api/document_requests/__init__.py +0 -8
  260. tests/api/document_requests/test_document_requests.py +0 -131
  261. tests/api/document_requests/test_document_requests_permissions.py +0 -177
  262. tests/api/document_requests/test_notifications_filter.py +0 -36
  263. tests/api/ill/test_ill_brw_crud.py +0 -84
  264. tests/api/ill/test_ill_brw_reqs_patron_loan_create_action.py +0 -207
  265. tests/api/ill/test_ill_brw_reqs_patron_loan_extension_actions.py +0 -298
  266. tests/api/ill/test_ill_brw_reqs_permissions.py +0 -169
  267. tests/api/ill/test_ill_providers_permissions.py +0 -82
  268. tests/api/ils/__init__.py +0 -8
  269. tests/api/ils/documents/__init__.py +0 -8
  270. tests/api/ils/documents/test_document_crud.py +0 -57
  271. tests/api/ils/documents/test_document_permissions.py +0 -106
  272. tests/api/ils/documents/test_document_resolvers.py +0 -35
  273. tests/api/ils/eitems/__init__.py +0 -8
  274. tests/api/ils/eitems/test_eitems_crud.py +0 -41
  275. tests/api/ils/eitems/test_eitems_permissions.py +0 -84
  276. tests/api/ils/eitems/test_files.py +0 -172
  277. tests/api/ils/items/__init__.py +0 -8
  278. tests/api/ils/items/test_apis.py +0 -43
  279. tests/api/ils/items/test_items_crud.py +0 -60
  280. tests/api/ils/items/test_items_permissions.py +0 -107
  281. tests/api/ils/items/test_items_update.py +0 -47
  282. tests/api/ils/records_relations/__init__.py +0 -8
  283. tests/api/ils/records_relations/helpers.py +0 -115
  284. tests/api/ils/records_relations/test_records_relations_parentchild.py +0 -560
  285. tests/api/ils/records_relations/test_records_relations_sequence.py +0 -302
  286. tests/api/ils/records_relations/test_records_relations_siblings.py +0 -678
  287. tests/api/ils/series/__init__.py +0 -8
  288. tests/api/ils/series/test_series_permissions.py +0 -95
  289. tests/api/ils/test_anonymization.py +0 -189
  290. tests/api/ils/test_apis.py +0 -76
  291. tests/api/ils/test_closures.py +0 -324
  292. tests/api/ils/test_errors.py +0 -126
  293. tests/api/ils/test_facets.py +0 -84
  294. tests/api/ils/test_internal_locations.py +0 -96
  295. tests/api/ils/test_loaders.py +0 -55
  296. tests/api/ils/test_metadata_extensions.py +0 -205
  297. tests/api/ils/test_notifications.py +0 -183
  298. tests/api/ils/test_notifications_mails.py +0 -39
  299. tests/api/ils/test_notifications_permissions.py +0 -55
  300. tests/api/ils/test_patrons.py +0 -106
  301. tests/api/ils/test_record_delete.py +0 -46
  302. tests/api/ils/test_record_permissions.py +0 -135
  303. tests/api/ils/test_resolvers.py +0 -207
  304. tests/api/ils/test_stats.py +0 -160
  305. tests/api/ils/test_tasks.py +0 -211
  306. tests/api/ils/test_vocabularies.py +0 -35
  307. tests/conftest.py +0 -123
  308. tests/data/acq_orders.json +0 -89
  309. tests/data/acq_providers.json +0 -12
  310. tests/data/document_requests.json +0 -77
  311. tests/data/documents.json +0 -237
  312. tests/data/eitems.json +0 -66
  313. tests/data/ill_borrowing_requests.json +0 -77
  314. tests/data/ill_providers.json +0 -12
  315. tests/data/internal_locations.json +0 -22
  316. tests/data/items.json +0 -271
  317. tests/data/loans.json +0 -133
  318. tests/data/loans_most_loaned.json +0 -128
  319. tests/data/locations.json +0 -20
  320. tests/data/series.json +0 -33
  321. tests/helpers.py +0 -104
  322. tests/templates/notifications/title_body.html +0 -8
  323. tests/templates/notifications/title_body_html.html +0 -13
  324. tests/templates/notifications/title_body_html_ctx.html +0 -13
  325. tests/templates/notifications/title_only.html +0 -3
  326. tests/test_version.py +0 -17
  327. /tests/templates/notifications/blank.html → /invenio_app_ils/acquisition/mappings/os-v1/__init__.py +0 -0
  328. /invenio_app_ils/stats/aggregations/aggr_file_download/{v6 → os-v1}/__init__.py +0 -0
  329. /invenio_app_ils/stats/file_download/{v6 → os-v1}/__init__.py +0 -0
  330. {invenio_app_ils-1.0.0a54.dist-info → invenio_app_ils-6.1.0.dist-info/licenses}/AUTHORS.rst +0 -0
  331. {invenio_app_ils-1.0.0a54.dist-info → invenio_app_ils-6.1.0.dist-info/licenses}/LICENSE +0 -0
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
- # Copyright (C) 2018-2020 CERN.
3
+ # Copyright (C) 2018-2025 CERN.
4
4
  #
5
5
  # invenio-app-ils is free software; you can redistribute it and/or modify it
6
6
  # under the terms of the MIT License; see LICENSE file for more details.
@@ -12,7 +12,6 @@ from copy import copy, deepcopy
12
12
  from datetime import date, timedelta
13
13
  from functools import partial
14
14
 
15
- from elasticsearch import VERSION as ES_VERSION
16
15
  from flask import current_app
17
16
  from flask_login import current_user
18
17
  from invenio_circulation.config import (
@@ -27,14 +26,22 @@ from invenio_db import db
27
26
  from invenio_pidstore.models import PIDStatus
28
27
  from invenio_pidstore.providers.recordid_v2 import RecordIdProviderV2
29
28
 
29
+ from invenio_app_ils.circulation.notifications.api import (
30
+ send_dates_updated_notification,
31
+ )
30
32
  from invenio_app_ils.circulation.search import (
31
- get_all_range_expiring_ils_loans_by_patron_pid,
33
+ get_all_expiring_or_overdue_loans_by_patron_pid,
32
34
  )
33
35
  from invenio_app_ils.errors import (
36
+ DocumentOverbookedError,
34
37
  IlsException,
35
38
  InvalidLoanExtendError,
36
39
  InvalidParameterError,
40
+ ItemCannotCirculateError,
41
+ ItemHasActiveLoanError,
42
+ ItemNotFoundError,
37
43
  MissingRequiredParameterError,
44
+ MultipleItemsBarcodeFoundError,
38
45
  PatronHasLoanOnDocumentError,
39
46
  PatronHasLoanOnItemError,
40
47
  PatronHasRequestOnDocumentError,
@@ -44,9 +51,6 @@ from invenio_app_ils.items.api import Item
44
51
  from invenio_app_ils.minters import pid_minter
45
52
  from invenio_app_ils.proxies import current_app_ils
46
53
 
47
- lt_es7 = ES_VERSION[0] < 7
48
-
49
-
50
54
  # override default `invenio-circulation` minters to use the base32 PIDs
51
55
  # CIRCULATION_LOAN_PID_TYPE is already defined in `invenio-circulation`
52
56
  ILS_CIRCULATION_LOAN_MINTER = "ilsloanid"
@@ -55,9 +59,7 @@ ILS_CIRCULATION_LOAN_FETCHER = "ilsloanid"
55
59
  IlsCirculationLoanIdProvider = type(
56
60
  "IlsCirculationLoanIdProvider",
57
61
  (RecordIdProviderV2,),
58
- dict(
59
- pid_type=CIRCULATION_LOAN_PID_TYPE, default_status=PIDStatus.REGISTERED
60
- ),
62
+ dict(pid_type=CIRCULATION_LOAN_PID_TYPE, default_status=PIDStatus.REGISTERED),
61
63
  )
62
64
  ils_circulation_loan_pid_minter = partial(
63
65
  pid_minter, provider_cls=IlsCirculationLoanIdProvider
@@ -79,9 +81,9 @@ def _validate_delivery(delivery):
79
81
  )
80
82
 
81
83
 
82
- def _set_item_to_can_circulate(item_pid):
84
+ def _set_item_to_can_circulate(item_pid_value):
83
85
  """Change the item status to CAN_CIRCULATE."""
84
- item = Item.get_record_by_pid(item_pid["value"])
86
+ item = Item.get_record_by_pid(item_pid_value)
85
87
  if item["status"] != "CAN_CIRCULATE":
86
88
  item["status"] = "CAN_CIRCULATE"
87
89
  item.commit()
@@ -91,16 +93,12 @@ def _set_item_to_can_circulate(item_pid):
91
93
 
92
94
  def patron_has_request_on_document(patron_pid, document_pid):
93
95
  """Return loan request for given patron and document."""
94
- states = (
95
- current_app.config["CIRCULATION_STATES_LOAN_REQUEST"]
96
- )
96
+ states = current_app.config["CIRCULATION_STATES_LOAN_REQUEST"]
97
97
  search = search_by_patron_item_or_document(
98
98
  patron_pid=patron_pid, document_pid=document_pid, filter_states=states
99
99
  )
100
100
  search_result = search.execute()
101
- total = (
102
- search_result.hits.total if lt_es7 else search_result.hits.total.value
103
- )
101
+ total = search_result.hits.total.value
104
102
  if total > 0:
105
103
  return search_result.hits[0]
106
104
  else:
@@ -117,9 +115,7 @@ def patron_has_active_loan_or_request_on_document(patron_pid, document_pid):
117
115
  patron_pid=patron_pid, document_pid=document_pid, filter_states=states
118
116
  )
119
117
  search_result = search.execute()
120
- total = (
121
- search_result.hits.total if lt_es7 else search_result.hits.total.value
122
- )
118
+ total = search_result.hits.total.value
123
119
  if total > 0:
124
120
  return search_result.hits[0]
125
121
  else:
@@ -131,7 +127,7 @@ def request_loan(
131
127
  patron_pid,
132
128
  transaction_location_pid,
133
129
  transaction_user_pid=None,
134
- **kwargs
130
+ **kwargs,
135
131
  ):
136
132
  """Create a new loan and trigger the first transition to PENDING."""
137
133
  loan_cls = current_circulation.loan_record_cls
@@ -179,11 +175,48 @@ def patron_has_active_loan_on_item(patron_pid, item_pid):
179
175
  filter_states=current_app.config["CIRCULATION_STATES_LOAN_ACTIVE"],
180
176
  )
181
177
  search_result = search.execute()
182
- return (
183
- search_result.hits.total > 0
184
- if lt_es7
185
- else search_result.hits.total.value > 0
178
+ return search_result.hits.total.value > 0
179
+
180
+
181
+ def _checkout_loan(
182
+ item_pid,
183
+ patron_pid,
184
+ transaction_location_pid,
185
+ trigger="checkout",
186
+ transaction_user_pid=None,
187
+ delivery=None,
188
+ **kwargs,
189
+ ):
190
+ """Checkout a loan."""
191
+ transaction_user_pid = transaction_user_pid or str(current_user.id)
192
+ loan_cls = current_circulation.loan_record_cls
193
+ # create a new loan
194
+ record_uuid = uuid.uuid4()
195
+ new_loan = dict(
196
+ patron_pid=patron_pid,
197
+ transaction_location_pid=transaction_location_pid,
198
+ transaction_user_pid=transaction_user_pid,
199
+ )
200
+
201
+ if delivery:
202
+ new_loan["delivery"] = delivery
203
+ # check if there is an existing request
204
+ loan = patron_has_request_on_document(patron_pid, kwargs.get("document_pid"))
205
+ if loan:
206
+ loan = loan_cls.get_record_by_pid(loan.pid)
207
+ pid = IlsCirculationLoanIdProvider.get(loan["pid"]).pid
208
+ loan.update(new_loan)
209
+ else:
210
+ pid = ils_circulation_loan_pid_minter(record_uuid, data=new_loan)
211
+ loan = loan_cls.create(data=new_loan, id_=record_uuid)
212
+
213
+ params = deepcopy(loan)
214
+ params.update(item_pid=item_pid, **kwargs)
215
+
216
+ loan = current_circulation.circulation.trigger(
217
+ loan, **dict(params, trigger=trigger)
186
218
  )
219
+ return pid, loan
187
220
 
188
221
 
189
222
  def checkout_loan(
@@ -192,7 +225,7 @@ def checkout_loan(
192
225
  transaction_location_pid,
193
226
  transaction_user_pid=None,
194
227
  force=False,
195
- **kwargs
228
+ **kwargs,
196
229
  ):
197
230
  """Create a new loan and trigger the first transition to ITEM_ON_LOAN.
198
231
 
@@ -207,61 +240,114 @@ def checkout_loan(
207
240
  the checkout. If False, the checkout will fail when the item cannot
208
241
  circulate.
209
242
  """
210
- loan_cls = current_circulation.loan_record_cls
211
- if patron_has_active_loan_on_item(
212
- patron_pid=patron_pid, item_pid=item_pid
213
- ):
243
+
244
+ if patron_has_active_loan_on_item(patron_pid=patron_pid, item_pid=item_pid):
214
245
  raise PatronHasLoanOnItemError(patron_pid, item_pid)
215
246
  optional_delivery = kwargs.get("delivery")
216
247
  if optional_delivery:
217
248
  _validate_delivery(optional_delivery)
218
249
 
219
250
  if force:
220
- _set_item_to_can_circulate(item_pid)
251
+ _set_item_to_can_circulate(item_pid["value"])
221
252
 
222
- transaction_user_pid = transaction_user_pid or str(current_user.id)
223
-
224
- # create a new loan
225
- record_uuid = uuid.uuid4()
226
- new_loan = dict(
227
- patron_pid=patron_pid,
228
- transaction_location_pid=transaction_location_pid,
253
+ return _checkout_loan(
254
+ item_pid,
255
+ patron_pid,
256
+ transaction_location_pid,
229
257
  transaction_user_pid=transaction_user_pid,
258
+ **kwargs,
230
259
  )
231
260
 
232
- # check if there is an existing request
233
- loan = patron_has_request_on_document(
234
- patron_pid, kwargs.get("document_pid")
235
- )
236
- if loan:
237
- loan = loan_cls.get_record_by_pid(loan.pid)
238
- pid = IlsCirculationLoanIdProvider.get(loan["pid"]).pid
239
- loan.update(new_loan)
240
- else:
241
- pid = ils_circulation_loan_pid_minter(record_uuid, data=new_loan)
242
- loan = loan_cls.create(data=new_loan, id_=record_uuid)
243
261
 
244
- params = deepcopy(loan)
245
- params.update(item_pid=item_pid, **kwargs)
262
+ def _ensure_item_loanable_via_self_checkout(item_pid_value):
263
+ """Self-checkout: return loanable item or raise when not loanable.
246
264
 
247
- # trigger the transition to request
248
- loan = current_circulation.circulation.trigger(
249
- loan, **dict(params, trigger="checkout")
265
+ Implements the self-checkout rules to loan an item.
266
+ """
267
+ item = current_app_ils.item_record_cls.get_record_by_pid(item_pid_value)
268
+ item_dict = item.replace_refs()
269
+
270
+ if item_dict["status"] == "MISSING":
271
+ _set_item_to_can_circulate(item_pid_value)
272
+ item = current_app_ils.item_record_cls.get_record_by_pid(item_pid_value)
273
+ item_dict = item.replace_refs()
274
+
275
+ if item_dict["status"] != "CAN_CIRCULATE":
276
+ raise ItemCannotCirculateError()
277
+
278
+ circulation_state = item_dict["circulation"].get("state")
279
+ has_active_loan = (
280
+ circulation_state and circulation_state in CIRCULATION_STATES_LOAN_ACTIVE
250
281
  )
282
+ if has_active_loan:
283
+ raise ItemHasActiveLoanError(loan_pid=item_dict["circulation"]["loan_pid"])
284
+
285
+ document = current_app_ils.document_record_cls.get_record_by_pid(
286
+ item_dict["document_pid"]
287
+ )
288
+ document_dict = document.replace_refs()
289
+ if document_dict["circulation"].get("overbooked", False):
290
+ raise DocumentOverbookedError(
291
+ f"Cannot self-checkout the overbooked document {item_dict['document_pid']}"
292
+ )
293
+
294
+ return item
251
295
 
252
- return pid, loan
296
+
297
+ def self_checkout_get_item_by_barcode(barcode):
298
+ """Search for an item by barcode.
299
+
300
+ :param barcode: the barcode of the item to search for
301
+ :return item: the item that was found, or raise in case of errors
302
+ """
303
+ item_search = current_app_ils.item_search_cls()
304
+ items = item_search.search_by_barcode(barcode).execute()
305
+ if items.hits.total.value == 0:
306
+ raise ItemNotFoundError(barcode=barcode)
307
+ if items.hits.total.value > 1:
308
+ raise MultipleItemsBarcodeFoundError(barcode)
309
+
310
+ item_pid = items.hits[0].pid
311
+ item = _ensure_item_loanable_via_self_checkout(item_pid)
312
+ return item_pid, item
313
+
314
+
315
+ def self_checkout(
316
+ item_pid, patron_pid, transaction_location_pid, transaction_user_pid=None, **kwargs
317
+ ):
318
+ """Perform self-checkout.
319
+
320
+ :param item_pid: a dict containing `value` and `type` fields to
321
+ uniquely identify the item.
322
+ :param patron_pid: the PID value of the patron
323
+ :param transaction_location_pid: the PID value of the location where the
324
+ checkout is performed
325
+ :param transaction_user_pid: the PID value of the user that performed the
326
+ checkout
327
+ """
328
+ _ensure_item_loanable_via_self_checkout(item_pid["value"])
329
+ return _checkout_loan(
330
+ item_pid,
331
+ patron_pid,
332
+ transaction_location_pid,
333
+ transaction_user_pid=transaction_user_pid,
334
+ trigger="self_checkout",
335
+ delivery=dict(method="SELF-CHECKOUT"),
336
+ **kwargs,
337
+ )
253
338
 
254
339
 
255
340
  def bulk_extend_loans(patron_pid, **kwargs):
256
341
  """Bulk extend qualified loans."""
257
342
  loan_class = current_circulation.loan_record_cls
258
- days = current_app.config["ILS_CIRCULATION_LOAN_WILL_EXPIRE_DAYS"]
259
343
 
260
- loans_search = get_all_range_expiring_ils_loans_by_patron_pid(
261
- expiring_in_days=days, patron_pid=patron_pid)
344
+ loans_search = get_all_expiring_or_overdue_loans_by_patron_pid(
345
+ patron_pid=patron_pid
346
+ )
262
347
 
263
348
  extended_loans = []
264
349
  not_extended_loans = []
350
+
265
351
  for loan in loans_search.scan():
266
352
  loan_record = loan_class.get_record_by_pid(loan["pid"])
267
353
  params = deepcopy(loan_record)
@@ -271,8 +357,8 @@ def bulk_extend_loans(patron_pid, **kwargs):
271
357
  **dict(
272
358
  params,
273
359
  trigger="extend",
274
- transition_kwargs=dict(send_notification=False)
275
- )
360
+ transition_kwargs=dict(send_notification=False),
361
+ ),
276
362
  )
277
363
  extended_loans.append(extended_loan)
278
364
  except (CirculationException, InvalidLoanExtendError):
@@ -292,14 +378,12 @@ def update_dates_loan(
292
378
  ):
293
379
  """Updates the dates of a loan."""
294
380
  state = record["state"]
295
- is_active_or_completed = (
296
- state in CIRCULATION_STATES_LOAN_ACTIVE
297
- or state in CIRCULATION_STATES_LOAN_COMPLETED
298
- )
381
+ is_active = state in CIRCULATION_STATES_LOAN_ACTIVE
382
+ is_completed = state in CIRCULATION_STATES_LOAN_COMPLETED
299
383
 
300
384
  data = copy(record)
301
385
 
302
- if is_active_or_completed:
386
+ if is_active or is_completed:
303
387
  today = date.today().strftime("%Y-%m-%d")
304
388
  if request_start_date or request_expire_date:
305
389
  raise IlsException(
@@ -320,8 +404,7 @@ def update_dates_loan(
320
404
  else: # Pending or cancelled
321
405
  if start_date or end_date:
322
406
  raise IlsException(
323
- description="Cannot modify dates of "
324
- "a pending or cancelled loan."
407
+ description="Cannot modify dates of " "a pending or cancelled loan."
325
408
  )
326
409
  if request_start_date:
327
410
  data["request_start_date"] = request_start_date
@@ -335,6 +418,9 @@ def update_dates_loan(
335
418
  db.session.commit()
336
419
  current_circulation.loan_indexer().index(record)
337
420
 
421
+ if is_active:
422
+ send_dates_updated_notification(record)
423
+
338
424
  return record
339
425
 
340
426
 
@@ -41,7 +41,7 @@ from invenio_app_ils.items.api import (
41
41
  )
42
42
  from invenio_app_ils.patrons.api import patron_exists
43
43
  from invenio_app_ils.permissions import (
44
- PatronOwnerPermission,
44
+ PatronOwnerReadPermission,
45
45
  authenticated_user_permission,
46
46
  backoffice_permission,
47
47
  loan_extend_circulation_permission,
@@ -51,11 +51,7 @@ from invenio_app_ils.permissions import (
51
51
 
52
52
  from .api import ILS_CIRCULATION_LOAN_FETCHER, ILS_CIRCULATION_LOAN_MINTER
53
53
  from .indexer import LoanIndexer
54
- from .jsonresolvers.loan import (
55
- document_resolver,
56
- item_resolver,
57
- loan_patron_resolver,
58
- )
54
+ from .jsonresolvers.loan import document_resolver, item_resolver, loan_patron_resolver
59
55
  from .notifications.api import circulation_filter_notifications
60
56
  from .transitions.transitions import ILSItemOnLoanToItemOnLoan, ILSToItemOnLoan
61
57
  from .utils import (
@@ -78,13 +74,17 @@ from .utils import (
78
74
  ILS_CIRCULATION_NOTIFICATION_OVERDUE_REMINDER_INTERVAL = 3
79
75
  #: The maximum duration of a loan request
80
76
  ILS_CIRCULATION_LOAN_REQUEST_DURATION_DAYS = 60
77
+ #: The minimum number of days after which a loan can start from the date of request
78
+ ILS_CIRCULATION_LOAN_REQUEST_OFFSET = 0
81
79
  #: Period of time in days, before loans expire, for notifications etc.
82
80
  ILS_CIRCULATION_LOAN_WILL_EXPIRE_DAYS = 7
83
81
  #: Optional delivery methods when requesting a new loan. Set to empty object to
84
82
  # disable it
85
83
  ILS_CIRCULATION_DELIVERY_METHODS = {
84
+ "NOT-SPECIFIED": "Not specified",
86
85
  "PICKUP": "Pick it up at the library desk",
87
86
  "DELIVERY": "Have it delivered to my office",
87
+ "SELF-CHECKOUT": "Self-checkout",
88
88
  }
89
89
 
90
90
  # Notification message creator for loan notifications
@@ -109,9 +109,7 @@ CIRCULATION_DOCUMENT_EXISTS = document_exists
109
109
 
110
110
  CIRCULATION_ITEM_LOCATION_RETRIEVER = circulation_item_location_retriever
111
111
 
112
- CIRCULATION_TRANSACTION_LOCATION_VALIDATOR = (
113
- circulation_transaction_location_validator
114
- )
112
+ CIRCULATION_TRANSACTION_LOCATION_VALIDATOR = circulation_transaction_location_validator
115
113
 
116
114
  CIRCULATION_TRANSACTION_USER_VALIDATOR = circulation_transaction_user_validator
117
115
 
@@ -134,9 +132,7 @@ CIRCULATION_POLICIES = dict(
134
132
 
135
133
  CIRCULATION_ITEM_REF_BUILDER = circulation_build_item_ref
136
134
 
137
- CIRCULATION_ITEM_RESOLVING_PATH = (
138
- "/api/resolver/circulation/loans/<loan_pid>/item"
139
- )
135
+ CIRCULATION_ITEM_RESOLVING_PATH = "/api/resolver/circulation/loans/<loan_pid>/item"
140
136
 
141
137
  CIRCULATION_ITEM_RESOLVER_ENDPOINT = item_resolver
142
138
 
@@ -150,9 +146,7 @@ CIRCULATION_DOCUMENT_RESOLVER_ENDPOINT = document_resolver
150
146
 
151
147
  CIRCULATION_PATRON_REF_BUILDER = circulation_build_patron_ref
152
148
 
153
- CIRCULATION_PATRON_RESOLVING_PATH = (
154
- "/api/resolver/circulation/loans/<loan_pid>/patron"
155
- )
149
+ CIRCULATION_PATRON_RESOLVING_PATH = "/api/resolver/circulation/loans/<loan_pid>/patron"
156
150
 
157
151
  CIRCULATION_PATRON_RESOLVER_ENDPOINT = loan_patron_resolver
158
152
 
@@ -171,6 +165,12 @@ CIRCULATION_LOAN_TRANSITIONS = {
171
165
  transition=ILSToItemOnLoan,
172
166
  permission_factory=backoffice_permission,
173
167
  ),
168
+ dict(
169
+ dest="ITEM_ON_LOAN",
170
+ trigger="self_checkout",
171
+ transition=ILSToItemOnLoan,
172
+ permission_factory=authenticated_user_permission,
173
+ ),
174
174
  ],
175
175
  "PENDING": [
176
176
  dict(
@@ -179,6 +179,12 @@ CIRCULATION_LOAN_TRANSITIONS = {
179
179
  transition=ILSToItemOnLoan,
180
180
  permission_factory=backoffice_permission,
181
181
  ),
182
+ dict(
183
+ dest="ITEM_ON_LOAN",
184
+ trigger="self_checkout",
185
+ transition=ILSToItemOnLoan,
186
+ permission_factory=authenticated_user_permission,
187
+ ),
182
188
  dict(
183
189
  dest="CANCELLED",
184
190
  trigger="cancel",
@@ -225,9 +231,7 @@ ILS_CIRCULATION_RECORDS_REST_ENDPOINTS = dict(
225
231
  record_class=Loan,
226
232
  indexer_class=LoanIndexer,
227
233
  record_loaders={
228
- "application/json": (
229
- "invenio_circulation.records.loaders:loan_loader"
230
- )
234
+ "application/json": "invenio_circulation.records.loaders:loan_loader"
231
235
  },
232
236
  record_serializers={
233
237
  "application/json": (
@@ -238,19 +242,19 @@ ILS_CIRCULATION_RECORDS_REST_ENDPOINTS = dict(
238
242
  "application/json": (
239
243
  "invenio_app_ils.circulation.serializers:json_v1_search"
240
244
  ),
241
- "text/csv": (
242
- "invenio_app_ils.circulation.serializers:csv_v1_search"
243
- ),
245
+ "text/csv": "invenio_app_ils.circulation.serializers:csv_v1_search",
246
+ },
247
+ search_serializers_aliases={
248
+ "csv": "text/csv",
249
+ "json": "application/json",
244
250
  },
245
251
  list_route="/circulation/loans/",
246
- item_route="/circulation/loans/<{0}:pid_value>".format(
247
- _LOANID_CONVERTER
248
- ),
252
+ item_route="/circulation/loans/<{0}:pid_value>".format(_LOANID_CONVERTER),
249
253
  default_media_type="application/json",
250
254
  links_factory_imp="invenio_circulation.links:loan_links_factory",
251
255
  max_result_window=RECORDS_REST_MAX_RESULT_WINDOW,
252
256
  error_handlers=dict(),
253
- read_permission_factory_imp=PatronOwnerPermission,
257
+ read_permission_factory_imp=PatronOwnerReadPermission,
254
258
  # auth via search_factory
255
259
  list_permission_factory_imp=authenticated_user_permission,
256
260
  create_permission_factory_imp=superuser_permission,
@@ -14,6 +14,7 @@ from flask import current_app
14
14
  from invenio_circulation.pidstore.pids import CIRCULATION_LOAN_PID_TYPE
15
15
  from invenio_circulation.proxies import current_circulation
16
16
  from invenio_indexer.api import RecordIndexer
17
+ from invenio_pidstore.errors import PIDDeletedError
17
18
 
18
19
  from invenio_app_ils.circulation.utils import resolve_item_from_loan
19
20
  from invenio_app_ils.documents.api import DOCUMENT_PID_TYPE
@@ -48,20 +49,15 @@ def index_referenced_records(loan):
48
49
  loan_class = current_circulation.loan_record_cls
49
50
  loan_record = loan_class.get_record_by_pid(loan["pid"])
50
51
 
51
- referenced.append(
52
- dict(pid_type=CIRCULATION_LOAN_PID_TYPE, record=loan_record)
53
- )
52
+ referenced.append(dict(pid_type=CIRCULATION_LOAN_PID_TYPE, record=loan_record))
54
53
 
55
54
  # add all the other loans, as after indexing this one, they
56
55
  # will be affected in search
57
- pending_loans = \
58
- document.search_loan_references().scan()
56
+ pending_loans = document.search_loan_references().scan()
59
57
 
60
58
  for loan_hit in pending_loans:
61
59
  pending_loan = loan_class.get_record_by_pid(loan_hit.pid)
62
- referenced.append(
63
- dict(pid_type=CIRCULATION_LOAN_PID_TYPE, record=pending_loan)
64
- )
60
+ referenced.append(dict(pid_type=CIRCULATION_LOAN_PID_TYPE, record=pending_loan))
65
61
 
66
62
  # index the loan and referenced records
67
63
  indexer.index(indexed, referenced)
@@ -86,19 +82,18 @@ def index_extra_fields_for_loan(loan_dict):
86
82
  details.
87
83
  """
88
84
  document_class = current_app_ils.document_record_cls
89
- document_record = document_class.get_record_by_pid(
90
- loan_dict.get("document_pid")
91
- )
85
+ try:
86
+ document_record = document_class.get_record_by_pid(loan_dict["document_pid"])
87
+ except PIDDeletedError:
88
+ # Document might have been deleted while reindexing asynchronously.
89
+ return
90
+
92
91
  document = document_record.replace_refs()
93
92
 
94
- items_available_for_loan_count = document.get("circulation", {}).get(
95
- "available_items_for_loan_count"
96
- )
97
- loan_dict[
93
+ items_available_for_loan_count = document["circulation"][
98
94
  "available_items_for_loan_count"
99
- ] = items_available_for_loan_count
95
+ ]
96
+ loan_dict["available_items_for_loan_count"] = items_available_for_loan_count
100
97
 
101
- can_circulate_items_count = document.get("circulation", {}).get(
102
- "can_circulate_items_count"
103
- )
98
+ can_circulate_items_count = document["circulation"]["can_circulate_items_count"]
104
99
  loan_dict["can_circulate_items_count"] = can_circulate_items_count
@@ -12,9 +12,11 @@ from invenio_app_ils.records.loaders import ils_marshmallow_loader
12
12
  from .schemas.json.bulk_extend import BulkExtendLoansSchemaV1
13
13
  from .schemas.json.loan_checkout import LoanCheckoutSchemaV1
14
14
  from .schemas.json.loan_request import LoanRequestSchemaV1
15
+ from .schemas.json.loan_self_checkout import LoanSelfCheckoutSchemaV1
15
16
  from .schemas.json.loan_update_dates import LoanUpdateDatesSchemaV1
16
17
 
17
18
  loan_request_loader = ils_marshmallow_loader(LoanRequestSchemaV1)
18
19
  loan_checkout_loader = ils_marshmallow_loader(LoanCheckoutSchemaV1)
20
+ loan_self_checkout_loader = ils_marshmallow_loader(LoanSelfCheckoutSchemaV1)
19
21
  loan_update_dates_loader = ils_marshmallow_loader(LoanUpdateDatesSchemaV1)
20
22
  loans_bulk_update_loader = ils_marshmallow_loader(BulkExtendLoansSchemaV1)
@@ -26,7 +26,7 @@ class LoanCheckoutSchemaV1(LoanBaseSchemaV1):
26
26
  item_pid = fields.Nested(LoanItemPIDSchemaV1, required=True)
27
27
  start_date = DateString()
28
28
  end_date = DateString()
29
- force = fields.Bool(missing=False)
29
+ force = fields.Bool(load_default=False)
30
30
 
31
31
  @validates("force")
32
32
  def validate_force(self, value, **kwargs):
@@ -57,8 +57,7 @@ class LoanCheckoutSchemaV1(LoanBaseSchemaV1):
57
57
  "The loan start date cannot be after the end date."
58
58
  ],
59
59
  "end_date": [
60
- "The loan end date cannot"
61
- " be before the start date."
60
+ "The loan end date cannot" " be before the start date."
62
61
  ],
63
62
  }
64
63
  )