Skip to content

Commit 2b7cc2a

Browse files
rerowepPascalRepond
andcommitted
feat(documents): allow deletion when acq order lines are terminal
* Closes rero#3225. * Add module-level constant `ACQ_ORDER_LINE_BLOCKING_STATUSES` (APPROVED, ORDERED, PARTIALLY_RECEIVED) in `documents/api.py` to avoid reallocating the list on every call to `get_links_to_me()`. * Filter the `acq_order_lines` link count by these blocking statuses so that order lines in a terminal state (RECEIVED, CANCELLED) no longer prevent document deletion. * Guard the receipt-line ES dumper against a missing document: when the document has already been deleted, fall back to the pid extracted from the `$ref` instead of raising an error. * Extend the reception-workflow test with `get_links_to_me()` assertions at each stage of the workflow, and verify that once all order lines are terminal the document reports no blocking links and no reasons not to delete. Co-Authored-by: Peter Weber <peter.weber@rero.ch> Co-Authored-by: Pascal Repond <pascal.repond@rero.ch>
1 parent d29392b commit 2b7cc2a

File tree

3 files changed

+36
-9
lines changed

3 files changed

+36
-9
lines changed

rero_ils/modules/acquisition/acq_receipt_lines/dumpers.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,16 @@ def dump(self, record, data):
5050
# Add document information's: pid, formatted title and ISBN identifiers
5151
# (remove None values from document metadata)
5252
document = order_line.document
53-
identifiers = document.get_identifiers(filters=[IdentifierType.ISBN], with_alternatives=True)
54-
identifiers = [identifier.normalize() for identifier in identifiers]
55-
data["document"] = {
56-
"pid": document.pid,
57-
"title": TitleExtension.format_text(document.get("title", [])),
58-
"identifiers": identifiers,
59-
}
60-
data["document"] = {k: v for k, v in data["document"].items() if v}
53+
if document:
54+
identifiers = document.get_identifiers(filters=[IdentifierType.ISBN], with_alternatives=True)
55+
identifiers = [identifier.normalize() for identifier in identifiers]
56+
data["document"] = {
57+
"pid": document.pid,
58+
"title": TitleExtension.format_text(document.get("title", [])),
59+
"identifiers": identifiers,
60+
}
61+
data["document"] = {k: v for k, v in data["document"].items() if v}
62+
else:
63+
# Document has been deleted; keep only the pid extracted from the $ref
64+
data["document"] = {"pid": order_line.document_pid}
6165
return data

rero_ils/modules/documents/api.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
from jsonschema.exceptions import ValidationError
3030

3131
from rero_ils.modules.acquisition.acq_order_lines.api import AcqOrderLinesSearch
32+
from rero_ils.modules.acquisition.acq_order_lines.models import AcqOrderLineStatus
3233
from rero_ils.modules.api import IlsRecord, IlsRecordsIndexer, IlsRecordsSearch
3334
from rero_ils.modules.commons.identifiers import IdentifierFactory, IdentifierType
3435
from rero_ils.modules.documents.tasks import reindex_document_items
@@ -57,6 +58,12 @@
5758
# fetcher
5859
document_id_fetcher = partial(id_fetcher, provider=DocumentProvider)
5960

61+
ACQ_ORDER_LINE_BLOCKING_STATUSES = [
62+
AcqOrderLineStatus.APPROVED,
63+
AcqOrderLineStatus.ORDERED,
64+
AcqOrderLineStatus.PARTIALLY_RECEIVED,
65+
]
66+
6067

6168
class DocumentsSearch(IlsRecordsSearch):
6269
"""DocumentsSearch."""
@@ -313,8 +320,14 @@ def get_links_to_me(self, get_pids=False):
313320
exclude_states=[LoanState.CANCELLED, LoanState.ITEM_RETURNED],
314321
)
315322
file_query = self.get_records_files_query().source()
316-
acq_order_lines_query = AcqOrderLinesSearch().filter("term", document__pid=self.pid)
323+
324+
acq_order_lines_query = (
325+
AcqOrderLinesSearch()
326+
.filter("term", document__pid=self.pid)
327+
.filter("terms", status=ACQ_ORDER_LINE_BLOCKING_STATUSES)
328+
)
317329
local_fields_query = LocalFieldsSearch().get_local_fields(self.provider.pid_type, self.pid)
330+
318331
relation_types = {
319332
"partOf": "partOf.document.pid",
320333
"supplement": "supplement.pid",

tests/api/acquisition/test_acquisition_reception_workflow.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ def test_acquisition_reception_workflow(
6464
document,
6565
):
6666
"""Test complete acquisition workflow."""
67+
assert document.get_links_to_me() == {}
6768

6869
def assert_account_data(accounts):
6970
"""Assert account informations."""
@@ -286,6 +287,8 @@ def assert_account_data(accounts):
286287
}
287288
assert_account_data(manual_controls)
288289

290+
assert document.get_links_to_me() == {"acq_order_lines": 6}
291+
289292
# STEP 3 :: UPDATE ORDER LINES
290293
# * Cancel some order lines and change some quantities --> make sure
291294
# calculations still good
@@ -363,6 +366,8 @@ def assert_account_data(accounts):
363366
assert order_line_1.unreceived_quantity == 5
364367
assert order_line_1.status == AcqOrderLineStatus.APPROVED
365368

369+
assert document.get_links_to_me() == {"acq_order_lines": 4}
370+
366371
# STEP 4 :: SEND THE ORDER
367372
# * Test send order and make sure statuses are up to date.
368373
# - check order lines (status, order-date)
@@ -611,6 +616,11 @@ def assert_account_data(accounts):
611616
}
612617
assert_account_data(manual_controls)
613618

619+
# All order lines are now RECEIVED or CANCELLED (no blocking statuses remain),
620+
# so the document should have no links preventing deletion.
621+
assert document.get_links_to_me() == {}
622+
assert document.reasons_not_to_delete() == {}
623+
614624
# TEST 8: DELETE RECEIPTS
615625
# * Delete the second receipt. This will also delete the related receipt
616626
# lines. The order status must remain to PARTIALLY_RECEIVED.

0 commit comments

Comments
 (0)