Several Changes, One Outcome · practice
Respect a Member's Loan Limit
Sam begins with one active loan and a stored limit of 2.5. The current 4 and item 5, producing three active loans.
The decision concerns the next whole loan:
| Active now | Stored limit | Next count | Allow? |
|---|---|---|---|
1 | 2.5 | 2 | Yes |
2 | 2.5 | 3 | No |
Open transactions.py. The member lookup and active-count queries are supplied. Inside the same connection context, after the item guard and before the insert, fetch the member row with (member_id,).
If the member exists, count only that member’s loans whose returned_on
active_count + 1 > loan_limit
Raise the exact message:
raise ValueError("That member has reached the loan limit.")
Do not round loan_limit. Each checkout adds one whole loan, and the direct comparison gives the documented boundary: 2 <= 2.5 is true, while 3 <= 2.5 is false. Returned loans do not count.
If the member lookup returns None, skip this application check. The later insert will reach the sqlite3.IntegrityError, preserving the behavior callers already know for a missing parent.
Press Run. The active-item call remains unchanged. Sam’s first available-item call returns 8101. The second should now show:
ValueError: That member has reached the loan limit.
Reopened active loans for MB-028: 2
Submit covers an empty count, one remaining place, an exactly full member, returned history, and the 2.5 boundary. It also verifies that counts belong to the proposed member only, successful work is durable, missing parents remain integrity errors, and the original connection stays usable.
One checkout now carries both application rules in one
Task
Extend checkout_loan with the member-limit guard inside its existing connection context.
Fetch the member’s loan_limit, count only that member’s active loans, and allow the insert exactly when active_count + 1 <= loan_limit. Raise ValueError("That member has reached the loan limit.") when full. A missing member must still reach the IntegrityError.