Skip to content

Conversation

@rerowep
Copy link
Contributor

@rerowep rerowep commented Jan 6, 2026

@coderabbitai
Copy link

coderabbitai bot commented Jan 6, 2026

Walkthrough

Multiple modules updated with defensive programming improvements (isinstance checks), batch operation optimizations for reindexing and data deletion, rounding consistency in financial calculations, and docstring refinements. Changes affect acquisition accounts, rollover processes, API utilities, serializers, and tests.

Changes

Cohort / File(s) Change Summary
Acquisition Accounts Financial Logic
rero_ils/modules/acquisition/acq_accounts/api.py
Updated allocated_amount calculations in transfer_fund method to consistently round to 2 decimals across all branches (CASE 1–3); docstring improvements for return value descriptions and balance calculation terminology.
Rollover Batch Processing
rero_ils/modules/acquisition/rollover.py
Introduced batching for order line migrations; changed AcqOrderLine.create from reindex=True to reindex=False and accumulated newly created lines for a single batch reindex pass after all lines processed.
API Defensive Improvements
rero_ils/modules/api.py
Replaced type equality assertions with isinstance checks for list validation; improved get_records_by_terms field handling; added defensive copy of endpoints dictionary; refined id validation logic; optimized get_all_pids/get_all_ids with yield_per(limit) for memory efficiency.
Serializer Type Checking
rero_ils/modules/serializers/mixins.py
Replaced strict type equality assertion with isinstance check for pids parameter validation in CachedDataSerializerMixin.load_resources.
Test Batch Deletion
tests/ui/holdings/test_holdings_item.py
Refactored item deletion loop to batch approach: schedule all deletions with dbcommit=False and delindex=True, then perform single ItemsSearch.flush_and_refresh() after loop completion.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Out of Scope Changes check ❓ Inconclusive Changes to api.py and serializers/mixins.py involve assertion/type-checking improvements and memory-efficient fetching unrelated to rollover fixes, though supporting refactoring is present alongside core fixes. Clarify whether defensive type checks and pagination refactoring in api.py/serializers/mixins.py are essential rollover dependencies or should be separated into a distinct maintenance PR.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix(acquisition): rollover' is concise and directly relates to the main change—fixing rollover functionality in the acquisition module.
Description check ✅ Passed The description clearly outlines the two key fixes (rollover order line creation and fund transfer rounding) and references the linked issue, all related to the changeset.
Linked Issues check ✅ Passed The code changes in rollover.py implement batch reindexing for order line migrations, and acquisition API adds rounding to allocated_amount transfers, addressing issue #3996's requirement to enable order line creation during rollover and properly handle fund transfers.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a4f9b32 and 54cf4e8.

📒 Files selected for processing (5)
  • rero_ils/modules/acquisition/acq_accounts/api.py
  • rero_ils/modules/acquisition/rollover.py
  • rero_ils/modules/api.py
  • rero_ils/modules/serializers/mixins.py
  • tests/ui/holdings/test_holdings_item.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • tests/ui/holdings/test_holdings_item.py
  • rero_ils/modules/api.py
  • rero_ils/modules/serializers/mixins.py
🧰 Additional context used
🧬 Code graph analysis (1)
rero_ils/modules/acquisition/rollover.py (3)
rero_ils/modules/acquisition/acq_order_lines/api.py (2)
  • AcqOrderLine (62-303)
  • create (108-114)
rero_ils/modules/acquisition/acq_orders/api.py (1)
  • create (107-112)
rero_ils/modules/acquisition/exceptions.py (1)
  • RolloverError (28-29)
🪛 Ruff (0.14.10)
rero_ils/modules/acquisition/rollover.py

444-444: Avoid specifying long messages outside the exception class

(TRY003)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: test (dev)
  • GitHub Check: test (deploy)
🔇 Additional comments (13)
rero_ils/modules/acquisition/rollover.py (7)

413-446: LGTM! Batching optimization improves performance.

The deferred reindexing pattern is well-implemented:

  • Order lines are created with reindex=False and accumulated in new_order_lines
  • After all creates complete, a single pass reindexes all lines
  • This reduces ES indexing overhead during bulk migration

The exception handling at line 443-444 ensures that if any order line creation fails, _abort_rollover will clean up all created objects from the _stack, maintaining data consistency.

📝 Note on the static analysis hint (optional improvement)

The static analysis tool flags line 444 for having a long message in the exception. While this works correctly, you could optionally extract the error message to a constant or use a shorter inline message if you want to align with the hint. However, this is a low-priority stylistic suggestion.


127-136: Docstring formatting improvements.

The parameter descriptions are now more readable with clearer formatting.


504-504: Docstring clarification.

Minor wording improvement for clarity.


549-551: Docstring formatting improvements.

Parameter descriptions are now better formatted and more readable.


584-587: Docstring clarification.

Validation requirements are now more clearly stated.


629-632: Docstring enhancement.

The description now provides better context about which orders need migration.


652-654: Docstring clarification.

The explanation of valid order line states is now clearer.

rero_ils/modules/acquisition/acq_accounts/api.py (6)

285-354: Critical fix: Rounding prevents floating-point precision errors in financial calculations.

All fund transfers now round allocated_amount to 2 decimal places across all three transfer cases (ancestor, same tree, different trees). This is essential for financial accuracy and prevents accumulation of floating-point precision errors over multiple operations.

The typo fix on line 285 ("availabe" → "available") also improves the documentation quality.


171-175: Docstring formatting improvements.

The return value description is now more clearly formatted and easier to read.


202-203: Docstring formatting improvements.

Return value description is now better formatted.


233-236: Docstring clarification.

The balance calculation description now more clearly explains the relationship between initial amount, encumbrance, expenditure, and distribution to children accounts.


267-267: Docstring parameter clarification.

Parameter description is now more explicit about the expected type.


379-379: Docstring parameter clarification.

The get_pids parameter behavior is now more clearly documented.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI Agents
In @rero_ils/modules/acquisition/rollover.py:
- Around line 33-34: Add the missing comma after AcqOrderLineIndexer in the
import/listing where AcqOrderLine, AcqOrderLineIndexer and AcqOrderLinesSearch
are declared to fix the syntax error; locate the sequence containing the symbol
AcqOrderLineIndexer in rollover.py and insert the comma so the tokens read
"AcqOrderLine, AcqOrderLineIndexer, AcqOrderLinesSearch".
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ced9e74 and 1dff508.

📒 Files selected for processing (3)
  • rero_ils/modules/acquisition/acq_accounts/api.py
  • rero_ils/modules/acquisition/rollover.py
  • rero_ils/modules/api.py
🧰 Additional context used
🧬 Code graph analysis (1)
rero_ils/modules/api.py (2)
rero_ils/modules/users/api.py (1)
  • fields (213-215)
rero_ils/modules/entities/remote_entities/replace.py (1)
  • query (115-122)
🪛 GitHub Actions: CI
rero_ils/modules/acquisition/rollover.py

[error] 34-34: SyntaxError: invalid syntax

🔇 Additional comments (9)
rero_ils/modules/acquisition/acq_accounts/api.py (2)

171-176: LGTM: Docstring improvements.

The docstring updates improve clarity and fix a typo ("availabe" → "available" on Line 285).

Also applies to: 202-203, 233-236, 267-267, 285-285, 379-379


304-304: LGTM: Monetary rounding for fund transfers.

Rounding allocated amounts to 2 decimals ensures consistent precision during fund transfers between accounts. This addresses potential floating-point arithmetic issues that could accumulate errors in financial calculations.

Also applies to: 326-326, 338-338, 349-349, 352-352

rero_ils/modules/acquisition/rollover.py (2)

413-413: LGTM: Batch reindexing optimization.

Deferring reindexing by creating order lines with reindex=False, accumulating them in a list, and then reindexing in batch (Lines 445-446) is a significant performance improvement. This avoids per-item index operations during the rollover process, which can be slow when processing many order lines.

Also applies to: 436-437, 445-446


128-136: LGTM: Docstring formatting improvements.

The docstring updates improve consistency and readability.

Also applies to: 504-504, 548-551, 584-587, 629-632, 652-654

rero_ils/modules/api.py (5)

131-131: LGTM: Improved type checking with isinstance.

Using isinstance(pids, list) is more Pythonic and handles subclasses correctly compared to type(pids) is list.


148-151: LGTM: Explicit None check for fields parameter.

The conditional now explicitly checks if fields is not None, which is clearer and correctly distinguishes between None and empty list [].


175-175: LGTM: Defensive copy prevents config mutation.

Creating a shallow copy of the endpoints dictionary before updating it prevents unintended modification of the application configuration.


252-252: LGTM: Explicit None check improves clarity.

Changing from if not id_: to if id_ is None: is more explicit and correctly handles cases where id_ might be a falsy but valid value (though UUID objects are unlikely to be falsy).


340-341: LGTM: Memory-efficient pagination with yield_per.

Replacing manual pagination with SQLAlchemy's yield_per(limit) is the recommended approach for memory-efficient iteration over large result sets. This prevents loading all records into memory at once.

Also applies to: 347-348

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
rero_ils/modules/api.py (1)

287-287: Inconsistent type check: should use isinstance here too.

Line 131 was updated to use isinstance(pids, list), but this line still uses the older type(pids) is list pattern. For consistency and to handle subclasses, this should be updated as well.

🔎 Proposed fix
-        assert type(pids) is list
+        assert isinstance(pids, list)
rero_ils/modules/acquisition/acq_accounts/api.py (1)

171-175: Docstring improvements are acceptable.

Minor formatting and wording adjustments improve clarity without changing functionality. Note: Line 171 has a typo "acqz" instead of "acq" in the docstring.

🔎 Proposed fix for typo
-            * APPROVED or ORDERED acqz order lines related to this account.
+            * APPROVED or ORDERED acq order lines related to this account.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1dff508 and 1e4d7fc.

📒 Files selected for processing (3)
  • rero_ils/modules/acquisition/acq_accounts/api.py
  • rero_ils/modules/acquisition/rollover.py
  • rero_ils/modules/api.py
🧰 Additional context used
🧬 Code graph analysis (1)
rero_ils/modules/acquisition/rollover.py (2)
rero_ils/modules/acquisition/acq_order_lines/api.py (1)
  • create (108-114)
rero_ils/modules/acquisition/exceptions.py (1)
  • RolloverError (28-29)
🪛 Ruff (0.14.10)
rero_ils/modules/acquisition/rollover.py

444-444: Avoid specifying long messages outside the exception class

(TRY003)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: test (dev)
  • GitHub Check: test (deploy)
🔇 Additional comments (11)
rero_ils/modules/acquisition/rollover.py (3)

32-35: Import statement is now correct.

The previous syntax error has been resolved. AcqOrderLineIndexer is no longer imported since the batched reindexing now calls reindex() directly on each record instance.


413-446: Good optimization: Batched reindexing improves rollover performance.

Deferring reindexing until all order lines are created reduces overhead during the migration loop. The approach is sound.

One consideration: if reindex() fails for any item in the final loop (lines 445-446), the records will exist in the database but may not be fully indexed. This is a minor edge case since reindex failures are rare after successful creation, and the records would still be recoverable.

For future optimization, consider using bulk indexing:

# Alternative approach using bulk indexer
from rero_ils.modules.acquisition.acq_order_lines.api import AcqOrderLinesIndexer
# ...
if new_order_lines:
    indexer = AcqOrderLinesIndexer()
    indexer.bulk_index([line.id for line in new_order_lines])

128-136: Docstring improvements look good.

The reformatted docstrings improve readability without changing behavior.

rero_ils/modules/api.py (6)

131-131: Good: Using isinstance for type checking.

This is more Pythonic and handles subclasses properly.


148-151: Good defensive handling of fields parameter.

When fields is None, omitting the source() call entirely is safer than passing an empty or None value to includes, which could cause unexpected behavior in some Elasticsearch versions.


175-176: Good: Defensive copy prevents config mutation.

Creating a copy before calling update() prevents the RECORDS_REST_ENDPOINTS config dictionary from being mutated with circulation endpoints, which could cause subtle bugs if this method is called multiple times or if other code relies on the original config state.


252-253: Good: More precise None check for id_.

Using if id_ is None instead of if not id_ is correct here. While UUIDs won't be falsy values like 0 or "", explicit None checking is clearer and more intentional for this context.


340-341: Good: Memory-efficient iteration with yield_per.

Using yield_per(limit) instead of manual pagination is cleaner and more memory-efficient for large result sets. This delegates batching to SQLAlchemy, which handles the cursor-based iteration properly.


347-348: Consistent with get_all_pids above.

Same memory-efficient pattern applied correctly.

rero_ils/modules/acquisition/acq_accounts/api.py (2)

304-304: Good: Rounding monetary amounts to 2 decimal places.

This addresses floating-point precision issues when transferring funds between accounts. The rounding is correctly applied in all branches of the transfer_fund method (CASE 1, 2, and 3).


326-352: Consistent rounding applied across all fund transfer cases.

All allocated_amount updates in CASE 2 (lines 326, 338) and CASE 3 (lines 349, 352) correctly apply round(..., 2) to prevent floating-point precision issues in monetary calculations. This is consistent with CASE 1 (line 304).

@github-actions github-actions bot added the developers From a developer point of view. label Jan 6, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI Agents
In @scripts/test:
- Around line 76-77: The test script is exempting CVE-2025-53000 without
justification; update the exemption by either upgrading the pinned nbconvert
version to a patched release (replace the nbconvert 7.16.6 reference) or, if you
must keep the exemption, replace the bare add_exceptions "CVE-2025-53000" entry
with a clear inline justification comment explaining why this uncontrolled
search-path execution risk is acceptable in our environment and list any
mitigations (e.g., OS restrictions, non-Windows deployment, container isolation,
CI constraints); ensure the change is applied next to the add_exceptions call so
reviewers can see the decision and mitigation.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1e4d7fc and bb460a6.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • rero_ils/modules/acquisition/acq_accounts/api.py
  • rero_ils/modules/acquisition/rollover.py
  • rero_ils/modules/api.py
  • rero_ils/modules/serializers/mixins.py
  • scripts/test
🧰 Additional context used
🧬 Code graph analysis (2)
rero_ils/modules/acquisition/acq_accounts/api.py (3)
rero_ils/modules/api.py (3)
  • update (382-411)
  • dbcommit (444-449)
  • reindex (451-456)
rero_ils/modules/acquisition/acq_order_lines/api.py (1)
  • update (116-132)
rero_ils/modules/acquisition/acq_receipts/api.py (1)
  • update (110-137)
rero_ils/modules/acquisition/rollover.py (2)
rero_ils/modules/acquisition/acq_orders/api.py (1)
  • create (107-112)
rero_ils/modules/acquisition/exceptions.py (1)
  • RolloverError (28-29)
🪛 Ruff (0.14.10)
rero_ils/modules/acquisition/rollover.py

444-444: Avoid specifying long messages outside the exception class

(TRY003)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: test (deploy)
  • GitHub Check: test (dev)
🔇 Additional comments (11)
rero_ils/modules/serializers/mixins.py (1)

170-170: LGTM: More Pythonic type checking.

The change from type(pids) is list to isinstance(pids, list) is a good practice that allows list subclasses while maintaining type safety. This aligns with similar improvements across the PR.

rero_ils/modules/api.py (6)

131-131: LGTM: More Pythonic type checking.

Consistent with the broader refactoring across the PR to use isinstance() for type checking.


175-176: LGTM: Defensive config copying.

Creating a copy before mutation prevents unintended side effects on the shared config dictionary.


252-253: LGTM: Explicit None checking.

Changing from if not id_: to if id_ is None: is more precise and distinguishes None from other falsy values like 0 or empty strings.


340-341: LGTM: Memory-efficient pagination.

Using yield_per(limit) is a SQLAlchemy optimization that streams results efficiently without loading all identifiers into memory at once.

Also applies to: 347-348


287-287: LGTM: Consistent type checking.

Matches the isinstance() pattern used throughout the PR.


148-151: No behavioral impact from field filtering logic change.

The code now uses if fields is not None: instead of if fields:, which changes handling of empty lists: previously an empty list would skip field filtering (returning all fields), while now it applies source(includes=[]) (returning no fields). However, all six callers in the codebase pass either explicit non-empty field lists or use the default None, so this change has no practical impact. If the new behavior (empty list → no fields) is intentional, this is semantically more correct and requires no action.

rero_ils/modules/acquisition/rollover.py (2)

413-413: LGTM: Efficient batched reindexing implementation.

The change to defer reindexing until after all order lines are created is a solid performance optimization:

  • Individual order lines are created with reindex=False (line 436)
  • Lines are accumulated in new_order_lines (line 437)
  • A final reindex pass processes all lines together (lines 445-446)

This reduces index operations from N individual reindexes to a single batch, significantly improving rollover performance. The approach aligns well with the PR objectives for deferred batch reindexing.

Also applies to: 436-437, 445-446


128-136: LGTM: Docstring formatting improvements.

The docstring refinements improve readability without changing functionality.

Also applies to: 504-504, 549-551, 584-587, 629-632, 652-654

rero_ils/modules/acquisition/acq_accounts/api.py (2)

304-304: LGTM: Critical monetary precision fix.

The addition of rounding to 2 decimals for all allocated_amount updates is essential for financial accuracy:

  • Prevents floating-point precision errors from accumulating
  • Ensures monetary values maintain standard currency precision (cents)
  • Applied consistently across all three transfer cases

This directly addresses the PR objective to "round allocated amount when transferring funds between accounts."

Also applies to: 326-326, 338-338, 349-349, 352-352


171-175: LGTM: Docstring formatting refinements.

The docstring improvements enhance readability and maintain consistency across the codebase.

Also applies to: 202-203, 233-236, 267-267, 285-285, 379-379

@coveralls
Copy link

coveralls commented Jan 6, 2026

Coverage Status

Changes unknown
when pulling 54cf4e8 on rerowep:wep-fix-rollover
into ** on rero:staging**.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses acquisition rollover issues and includes several code quality improvements. The main focus is on fixing rollover order line creation and ensuring accurate financial calculations when transferring funds between accounts.

Key changes:

  • Optimizes rollover process by deferring order line reindexing until after all lines are created
  • Adds rounding to 2 decimal places for allocated amounts during fund transfers to prevent floating-point precision errors
  • Refactors code to use isinstance() instead of type() comparisons and improves query efficiency with yield_per()

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
File Description
uv.lock Updates dependency versions (filelock 3.20.0→3.20.2, marshmallow 3.26.1→3.26.2, sqlalchemy 2.0.45 with additional wheel files)
tests/ui/holdings/test_holdings_item.py Refactors item deletion loop to collect PIDs first and defer commits for better performance
scripts/test Adds CVE-2025-53000 exception for nbconvert 7.16.6 vulnerability
rero_ils/modules/serializers/mixins.py Changes type check from type() to isinstance() for better Python practices
rero_ils/modules/api.py Multiple improvements: adds .copy() to prevent config mutation, uses isinstance() for type checks, improves None checking, refactors get_records_by_terms() to conditionally apply source filtering, and simplifies get_all_pids()/get_all_ids() using yield_per()
rero_ils/modules/acquisition/rollover.py Optimizes order line migration by deferring reindexing (creates with reindex=False, then bulk reindexes), and reformats multi-line docstrings for readability
rero_ils/modules/acquisition/acq_accounts/api.py Adds round(..., 2) to all allocated amount arithmetic in transfer_fund() to prevent floating-point precision errors in financial calculations, and reformats docstrings

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

@PascalRepond PascalRepond left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A test for rollover permissions would be nice.

* Fixes creation of rollover orders lines for not pending orders during
  rollover.
* Rounds allocated amount when transferring funds between accounts.
* Closes rero#3996

Co-Authored-by: Peter Weber <[email protected]>
@github-actions github-actions bot removed the developers From a developer point of view. label Jan 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rollover: order line creation can fail because of validation

3 participants