Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,13 @@ public function requestReservation(Request $request, ResponseInterface $response

// Decide loan vs reservation using the SAME availability gate the web
// uses (ReservationManager), so the two surfaces agree. Immediate loan
// only when the user asked for "now" (no date) and a copy is free.
// when the user asked for "now" — either no date, OR today's date with
// a copy free. The app's "Request loan" on an available title sends
// today (its date picker pre-selects the first free day = today), so
// without the today case that flow wrongly became a reservation
// instead of a pending loan. A FUTURE date is always a reservation.
$immediate = false;
if ($desired === '') {
if ($desired === '' || $desired === date('Y-m-d')) {
$manager = new \App\Controllers\ReservationManager($this->db);
$immediate = $manager->isBookAvailableForImmediateLoan($bookId, null, null, $userId);
}
Expand Down
21 changes: 21 additions & 0 deletions tests/mobile-api-behaviors.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -600,4 +600,25 @@ test.describe('Reservations', () => {
clearBorrowerReservations();
}
});

test('26) {available book, desired_date=today} → immediate loan (type=loan), not a reservation', async ({ request }) => {
// The app's "Request loan" on an AVAILABLE title sends today's date (its
// date picker pre-selects the first free day = today). The backend must
// treat today + a free copy as an immediate pending loan, not a
// reservation — otherwise the available-now flow silently queues instead
// of requesting a loan. A FUTURE date stays a reservation (test 22).
clearBorrowerReservations();
try {
const book = pickAvailableBook();
const res = await call(request, 'POST', '/reservations', {
token: ctx.userToken,
body: { book_id: book, desired_date: todayYmd() },
});
expect(res.status(), 'created').toBe(201);
const j = await jsonOf(res);
expect(j?.data?.type, 'today + available → immediate loan').toBe('loan');
} finally {
clearBorrowerReservations();
}
});
});
Loading