Whilst working on the lead/trail time addition to bookings we discussed how they should affect things. In the end we decided that they should work in combination when placing bookings so the window of unbookable time before a bookings should be the previous bookings 'trail' period + the current bookings 'lead' period. I've run out of capacity to make that change in the aforementioned bug, so I'm splitting it out here to work on that as a expedient follow-up. Lets get the core functionality in and then continue to polish it. A- | TA >|< LB | -B- | TB >|< LC | -C
*** Bug 39390 has been marked as a duplicate of this bug. ***
Created attachment 182718 [details] [review] Bug 37707: First draft This patch adds calculation of pre and post booking days into the disableDate function. I'm not sure I like it for display yet, but functionally it works
I can confirm this works as described -- bookings cannot be created such that the trailing time of one booking intersects with the leading time of the next. The interface grays out dates that cannot be selected and changes the mouse icon to a crossed-out-circle. Martin, what do you still feel is missing in the display here? Our libraries would love to see this functionality in Koha sooner rather than later.
We are eager to see this one move forward.
I'm still targeting 25.11 for this. There's been a few holdups in terms of getting consistent Cypress tests working upstream of this (I don't want to break existing functionality whilst working on this), and the test infrastructure has been changing multiple times whilst I've been working on that. There's also a Vue refactor of the current Modal code to make extending it simpler, which Paul has ready to submit. In short.. It's all just around the corner, but every time I hit it of late, I find the tides have shifted beneath my feet.
Created attachment 190859 [details] [review] Bug 37707: Add Cypress tests for bidirectional lead/trail period conflicts This enhances the bookings lead/trail period tests to validate that: - New booking's lead period respects existing bookings' trail periods - New booking's trail period respects existing bookings' lead periods Previously, we only checked: - New booking lead vs existing booking actual dates - New booking trail vs existing booking actual dates Now we also validate the full "protected period" concept where each existing booking reserves: lead + actual + trail period. Test timeline updated: - Booking A: Days 20-25 (protected: 18-28) - Booking B: Days 60-65 (protected: 58-68) New test coverage: - TEST 2B: New lead conflicts with existing trail (Days 27-30) - TEST 6B: New trail conflicts with existing lead (Days 55-56) - TEST 7: Valid booking window (Days 31-54) respecting both Current status: Tests FAIL as expected, revealing the bug that bidirectional checking is not yet implemented.
Created attachment 190860 [details] [review] Bug 37707: Improve lead/trail period conflict detection This implements the full "protected period" concept for bookings, where each existing booking reserves: lead period + actual dates + trail period. Previously, we only checked: - New booking lead vs existing booking actual dates - New booking trail vs existing booking actual dates Now we ALSO check: - New booking lead vs existing booking trail periods - New booking trail vs existing booking lead periods This ensures librarians cannot create bookings too close together, respecting both item preparation time (lead) and processing time (trail). Test plan: 1. Apply all patches and run: yarn build 2. Configure a bookable item with 2-day lead and 3-day trail periods 3. Create booking A: January 5-9 - This reserves Jan 3-4 (lead), Jan 5-9 (actual), Jan 10-12 (trail) 4. Attempt to create booking B: January 12-15 with 2-day lead - Lead would be Jan 10-11, which conflicts with booking A's trail 5. Verify days 10-11 are visually disabled with striped pattern 6. Verify hovering shows "conflicts with existing booking's trail period" 7. Verify you cannot select January 12 as start date 8. Verify January 13 IS selectable (no conflict) 9. Run Cypress tests to confirm: npx cypress run --spec "t/cypress/integration/Circulation/bookingsModalDatePicker_spec.ts"
Created attachment 190861 [details] [review] Bug 37707: (follow-up) Add visual refinements for existing booking lead/trail periods This patch enhances the visual presentation of existing bookings' protected periods (lead/trail) to match the polished appearance of new booking lead/trail period indicators. Test plan: 1. Apply all patches and run: yarn build 2. Configure a bookable item with 2-day lead and 2-day trail 3. Create an existing booking for January 10-15 4. Open the booking calendar for that item 5. Verify visual styling of protected periods: - Jan 8-9 (lead period): diagonal striped pattern, rounded left edge on Jan 8 - Jan 10-15 (booking): solid color fill - Jan 16-17 (trail period): diagonal striped pattern, rounded right edge on Jan 17 6. Verify no visual gaps between consecutive protected period dates 7. Verify the striped pattern is clearly distinguishable from solid booking dates 8. Hover over different date ranges and verify lead/trail styling updates correctly
Created attachment 190862 [details] [review] Bug 37707: (follow-up) Add textual feedback for booking lead/trail period conflicts This patch adds a feedback message container below the calendar that provides contextual information about lead/trail period requirements and conflicts improving accessibility. The feedback updates dynamically on hover, showing: - Info messages when hovering selectable dates - Error messages when hovering dates disabled due to conflicts - Specific explanations distinguishing between conflict types (e.g., new lead vs existing trail, new trail vs existing lead) This complements the visual color indicators by providing explicit textual explanations, improving accessibility and user understanding. Test plan: 1. Apply all patches and run: yarn build 2. Configure a bookable item with 2-day lead and 3-day trail 3. Create an existing booking for January 10-15 (protected: Jan 8-18) 4. Open the booking calendar and observe feedback area below calendar 5. Hover over Jan 12 (part of existing booking) - Verify message: "This date is part of an existing booking" 6. Hover over Jan 8 (existing booking's lead period) - Verify message explains it's part of the lead period 7. Try to select Jan 19-20 as booking dates (2-day lead = Jan 17-18) - Hover over Jan 19 when it appears disabled - Verify error message: "conflicts with existing booking's trail period" 8. Hover over Jan 21 (no conflicts) - Verify info message about lead/trail requirements 9. Verify all feedback messages are clear and helpful for librarians
Is this something that could be tested in a sandbox?
(In reply to Martin Renvoize (ashimema) from comment #9) > Created attachment 190862 [details] [review] [review] > Bug 37707: (follow-up) Add textual feedback for booking lead/trail period > conflicts This seems to be enforcing allowable dates correctly, but the messaging doesn't match what's given in the test plan and is not entirely accurate. Additionally, some messages use "lead period" and "trail period" which other use "preparation time" and "processing period." We should use "lead period" and "trail period" consistently. > 5. Hover over Jan 12 (part of existing booking) > - Verify message: "This date is part of an existing booking" Message I receive here is "Cannot select: Lead period (2 days before start) conflicts with existing booking." This is accurate in that the whole of the lead period for the new booking would be within the date range of the existing booking. But the test plan says I should just get told that the date I'm trying to select is within an existing booking and that would be a simpler message. > 6. Hover over Jan 8 (existing booking's lead period) > - Verify message explains it's part of the lead period Message I receive here is "Cannot select: Processing period (3 days after return) conflicts with existing booking's preparation time." This is potentially accurate -- if I'm trying to make a booking that starts on 1/8 and ends on 1/9, then the trail period of the new booking would include 1/9, which is in the lead period for my existing booking. But it would be more clear and true to tell me I can't start a booking on 1/8 because 1/8 is within the lead time for the existing booking. > 7. Try to select Jan 19-20 as booking dates (2-day lead = Jan 17-18) > - Hover over Jan 19 when it appears disabled > - Verify error message: "conflicts with existing booking's trail period" Hovering over 1/19 or 1/20, I get the message "Cannot select: Lead period (2 days before start) conflicts with existing booking." This is inaccurate. I should be told the new lead period would conflict with the existing trail period. Hovering over 1/16, 1/17, or 1/18, I get the message "Cannot select: Lead period (2 days before start) conflicts with existing item's processing time." This is inaccurate for 1/16; the lead time for a booking starting 1/16 would be fully within the existing booking rather than in its trail period. > 8. Hover over Jan 21 (no conflicts) > - Verify info message about lead/trail requirements These messages get confusing if I edit my circ rules so that I'm only setting a lead time *or* a trail time. If I put a 2 in "Booking pre-processing" and leave "Booking post-processing" blank, the circ rules interface actually saves a blank booking_trail_period value and then the message when placing a booking reads "Selecting end date. Processing period: days after return" It should either not mention lead periods or trail periods at all if the given value is blank. In fact, it should probably not mention them for values of 0, either. Additionally, if I have a lead period of 2 days defined and try to place a booking starting fewer than 2 days in the future, I get the message "Cannot select: Lead period (2 days before start) conflicts with existing booking." I get this message even on a record with no existing bookings at all. If I'm trying to select a date in the past, it should tell me I cannot select a date in the past. If I'm trying to select a date that would put my lead period in the past, it should tell me that the date cannot be selected because it would provide insufficient lead time.
Created attachment 191000 [details] [review] Bug 37707: Add Cypress tests for bidirectional lead/trail period conflicts This enhances the bookings lead/trail period tests to validate that: - New booking's lead period respects existing bookings' trail periods - New booking's trail period respects existing bookings' lead periods Previously, we only checked: - New booking lead vs existing booking actual dates - New booking trail vs existing booking actual dates Now we also validate the full "protected period" concept where each existing booking reserves: lead + actual + trail period. Test timeline updated: - Booking A: Days 20-25 (protected: 18-28) - Booking B: Days 60-65 (protected: 58-68) New test coverage: - TEST 2B: New lead conflicts with existing trail (Days 27-30) - TEST 6B: New trail conflicts with existing lead (Days 55-56) - TEST 7: Valid booking window (Days 31-54) respecting both Current status: Tests FAIL as expected, revealing the bug that bidirectional checking is not yet implemented.
Created attachment 191001 [details] [review] Bug 37707: Improve lead/trail period conflict detection This implements the full "protected period" concept for bookings, where each existing booking reserves: lead period + actual dates + trail period. Previously, we only checked: - New booking lead vs existing booking actual dates - New booking trail vs existing booking actual dates Now we ALSO check: - New booking lead vs existing booking trail periods - New booking trail vs existing booking lead periods This ensures librarians cannot create bookings too close together, respecting both item preparation time (lead) and processing time (trail). Test plan: 1. Apply all patches and run: yarn build 2. Configure a bookable item with 2-day lead and 3-day trail periods 3. Create booking A: January 5-9 - This reserves Jan 3-4 (lead), Jan 5-9 (actual), Jan 10-12 (trail) 4. Attempt to create booking B: January 12-15 with 2-day lead - Lead would be Jan 10-11, which conflicts with booking A's trail 5. Verify days 10-11 are visually disabled with striped pattern 6. Verify hovering shows "conflicts with existing booking's trail period" 7. Verify you cannot select January 12 as start date 8. Verify January 13 IS selectable (no conflict) 9. Run Cypress tests to confirm: npx cypress run --spec "t/cypress/integration/Circulation/bookingsModalDatePicker_spec.ts"
Created attachment 191002 [details] [review] Bug 37707: (follow-up) Add visual refinements for existing booking lead/trail periods This patch enhances the visual presentation of existing bookings' protected periods (lead/trail) to match the polished appearance of new booking lead/trail period indicators. Test plan: 1. Apply all patches and run: yarn build 2. Configure a bookable item with 2-day lead and 2-day trail 3. Create an existing booking for January 10-15 4. Open the booking calendar for that item 5. Verify visual styling of protected periods: - Jan 8-9 (lead period): diagonal striped pattern, rounded left edge on Jan 8 - Jan 10-15 (booking): solid color fill - Jan 16-17 (trail period): diagonal striped pattern, rounded right edge on Jan 17 6. Verify no visual gaps between consecutive protected period dates 7. Verify the striped pattern is clearly distinguishable from solid booking dates 8. Hover over different date ranges and verify lead/trail styling updates correctly
Created attachment 191003 [details] [review] Bug 37707: (follow-up) Add textual feedback for booking lead/trail period conflicts This patch adds a feedback message container below the calendar that provides contextual information about lead/trail period requirements and conflicts, improving accessibility and user understanding. The feedback updates dynamically on hover, showing: - Info messages when hovering selectable dates - Error messages when hovering dates disabled due to conflicts - Specific explanations distinguishing between conflict types (e.g., new lead vs existing trail, new trail vs existing lead) - Multiple conflict messages when both lead and trail periods conflict - Specific messages for past dates and insufficient lead time Key improvements: - Standardized terminology consistently uses "lead period" and "trail period" - Proper internationalization using __() for all user-facing strings - DRY code with detectPeriodConflict() helper function - Styling moved from inline JavaScript to SCSS using Bootstrap alert classes - Empty/zero periods are handled gracefully (not mentioned in messages) - Accurate conflict detection prioritizes what the hovered date IS over what it conflicts with This complements the visual color indicators by providing explicit textual explanations, improving accessibility and user understanding. Test plan: 1. Apply all patches and run: yarn build 2. Configure a bookable item with 2-day lead and 3-day trail periods 3. Create an existing booking for January 10-15 (protected: Jan 8-18) 4. Open the booking calendar and observe feedback area below calendar 5. Test past date and insufficient lead time messages: - Hover on today's date * Verify message: "Cannot select: Date is in the past" - Hover on tomorrow (with 2-day lead period) * Verify message: "Cannot select: Insufficient lead time (2 days required before start)" - Hover on the day after tomorrow * Verify message: "Cannot select: Insufficient lead time (2 days required before start)" * Should NOT show "conflicts with existing booking" if no booking exists 6. Test existing booking conflict messages: - Hover over Jan 12 (part of existing booking) * Verify message: "Cannot select: This date is part of an existing booking" - Hover over Jan 8 (existing booking's lead period) * Verify message: "Cannot select: This date is part of an existing booking's lead period" - Hover over Jan 16 (existing booking's trail period) * Verify message: "Cannot select: This date is part of an existing booking's trail period" 7. Test lead/trail period conflict messages: - Try to select Jan 19-20 as booking dates (2-day lead = Jan 17-18) - Hover over Jan 19 when it appears disabled * Verify error message: "Cannot select: Lead period (2 days before start) conflicts with existing booking's trail period" 8. Test info messages for valid dates: - Hover over Jan 21 (no conflicts, with lead period configured) * Verify info message: "Selecting start date. Lead period: 2 days before start" - Configure booking with NO lead period (0 or blank) - Hover over a valid date * Verify message: "Selecting start date" (no mention of lead period) 9. Test multiple conflict messages: - Position calendar to hover between two bookings where both lead and trail conflict * Verify message shows both conflicts separated by semicolon * Example: "Cannot select: lead period conflicts with existing booking's trail period; trail period conflicts with existing booking's lead period" 10. Verify all feedback messages: - Are properly translated (check .po files if applicable) - Use consistent "lead period" and "trail period" terminology - Are clear and helpful for librarians - Update color coding (red for errors, blue for info)
Thanks for the feedback Andrew, hopefully my replaced last patch makes the messages clearer. Kristi, yes you should be able to test this using a sandbox I believe.
Following the test plan in comment 15, I've run into some issues. I've got a bib with just 1 item on it. That item is bookable. After creating a booking for January 10-15, the calendar to create a new booking has January 10-16 greyed out, as if my booking were 10-16. In the calendar, mousing over days in the past gives error messages as if all past dates are part of an existing booking. When mousing over a date to select the start of a booking, the system gives feedback about the potential booking's trail period. I would suggest we should only give feedback about the potential booking's trail period when selecting the end of the potential booking. Until the user is proposing a booking end date, we cannot know what that booking's trail will conflict with. The datepicker and message area generally appeared above the Booking Dates input field. However, sometimes the datepicker and message area appeared below the input field instead. When this happened, the bottom of the message field pushed out of my window and could not be seen without zooming my browswer out. I was not able to scroll down to see the rest of the message. The messages contain inconsistent capitalization. Errors all start "Cannot select:" but the first word following that colon is sometimes capitalized and sometimes not. (In reply to Martin Renvoize (ashimema) from comment #15) > 6. Test existing booking conflict messages: > - Hover over Jan 12 (part of existing booking) > * Verify message: "Cannot select: This date is part of an existing > booking" This gives me the message "lead period conflicts with existing booking; trail period conflicts with an existing booking." The first statement will be true if I select 1/12 as the start of my booking. The second statement will be true if I select 1/12 as the end of my booking. In either case, the proposed message of "This date is part of an existing booking" would be more clear. > - Hover over Jan 8 (existing booking's lead period) > * Verify message: "Cannot select: This date is part of an existing > booking's lead period" This gives me the message "lead period conflicts with existing booking; trail period conflicts with existing booking's lead period." The first statement is *not* true, the lead period for a booking starting 1/8 would need to start 1/6, which is in the past and does not have a booking. > - Hover over Jan 16 (existing booking's trail period) > * Verify message: "Cannot select: This date is part of an existing > booking's trail period" This gives me the message "This date is part of an exiting booking." This is *not* true, 1/16 is part of the trail period of my existing booking.
In the first test I did, things looked almost right (the color-coding is really helpful) 1. Placed booking A for dates 1/12-1/17. Lead period should be 1/10 and 1/11. Trail period should be 1/18, 19, and 20. 2. Going to place booking B, and attempting to start my lead time on 1/20 is still allowing the booking without an error message. The message in blue reads "Selecting start date. Lead period: 2 days before start" screenshot attached (BookingBLeadConflic.png). With this booking, the lead time would start on 1/20, which is still the trail period for Booking A, and should be prevented. I was able to submit the booking (BookingBLeadConflict_table.png).
Created attachment 191232 [details] BookingBLeadConflic.png
Created attachment 191233 [details] BookingBLeadConflict_table.png
Created attachment 191350 [details] [review] Bug 37707: Add Cypress tests for bidirectional lead/trail period conflicts This enhances the bookings lead/trail period tests to validate that: - New booking's lead period respects existing bookings' trail periods - New booking's trail period respects existing bookings' lead periods Previously, we only checked: - New booking lead vs existing booking actual dates - New booking trail vs existing booking actual dates Now we also validate the full "protected period" concept where each existing booking reserves: lead + actual + trail period. Test timeline updated: - Booking A: Days 20-25 (protected: 18-28) - Booking B: Days 60-65 (protected: 58-68) New test coverage: - TEST 2B: New lead conflicts with existing trail (Days 27-30) - TEST 6B: New trail conflicts with existing lead (Days 55-56) - TEST 7: Valid booking window (Days 31-54) respecting both Current status: Tests FAIL as expected, revealing the bug that bidirectional checking is not yet implemented.
Created attachment 191351 [details] [review] Bug 37707: Improve lead/trail period conflict detection This implements the full "protected period" concept for bookings, where each existing booking reserves: lead period + actual dates + trail period. Previously, we only checked: - New booking lead vs existing booking actual dates - New booking trail vs existing booking actual dates Now we ALSO check: - New booking lead vs existing booking trail periods - New booking trail vs existing booking lead periods This ensures librarians cannot create bookings too close together, respecting both item preparation time (lead) and processing time (trail). Test plan: 1. Apply all patches and run: yarn build 2. Configure a bookable item with 2-day lead and 3-day trail periods 3. Create booking A: January 5-9 - This reserves Jan 3-4 (lead), Jan 5-9 (actual), Jan 10-12 (trail) 4. Attempt to create booking B: January 12-15 with 2-day lead - Lead would be Jan 10-11, which conflicts with booking A's trail 5. Verify days 10-11 are visually disabled with striped pattern 6. Verify hovering shows "conflicts with existing booking's trail period" 7. Verify you cannot select January 12 as start date 8. Verify January 13 IS selectable (no conflict) 9. Run Cypress tests to confirm: npx cypress run --spec "t/cypress/integration/Circulation/bookingsModalDatePicker_spec.ts"
Created attachment 191352 [details] [review] Bug 37707: (follow-up) Add visual refinements for existing booking lead/trail periods This patch enhances the visual presentation of existing bookings' protected periods (lead/trail) to match the polished appearance of new booking lead/trail period indicators. Test plan: 1. Apply all patches and run: yarn build 2. Configure a bookable item with 2-day lead and 2-day trail 3. Create an existing booking for January 10-15 4. Open the booking calendar for that item 5. Verify visual styling of protected periods: - Jan 8-9 (lead period): diagonal striped pattern, rounded left edge on Jan 8 - Jan 10-15 (booking): solid color fill - Jan 16-17 (trail period): diagonal striped pattern, rounded right edge on Jan 17 6. Verify no visual gaps between consecutive protected period dates 7. Verify the striped pattern is clearly distinguishable from solid booking dates 8. Hover over different date ranges and verify lead/trail styling updates correctly
Created attachment 191353 [details] [review] Bug 37707: (follow-up) Add textual feedback for booking lead/trail period conflicts This patch adds a feedback message container below the calendar that provides contextual information about lead/trail period requirements and conflicts, improving accessibility and user understanding. The feedback updates dynamically on hover, showing: - Info messages when hovering selectable dates - Error messages when hovering dates disabled due to conflicts - Specific explanations distinguishing between conflict types (e.g., new lead vs existing trail, new trail vs existing lead) - Multiple conflict messages when both lead and trail periods conflict - Specific messages for past dates and insufficient lead time Key improvements: - Standardized terminology consistently uses "lead period" and "trail period" - Proper internationalization using __() for all user-facing strings - DRY code with detectPeriodConflict() helper function - Styling moved from inline JavaScript to SCSS using Bootstrap alert classes - Empty/zero periods are handled gracefully (not mentioned in messages) - Accurate conflict detection prioritizes what the hovered date IS over what it conflicts with This complements the visual color indicators by providing explicit textual explanations, improving accessibility and user understanding. Test plan: 1. Apply all patches and run: yarn build 2. Configure a bookable item with 2-day lead and 3-day trail periods 3. Create an existing booking for January 10-15 (protected: Jan 8-18) 4. Open the booking calendar and observe feedback area below calendar 5. Test past date and insufficient lead time messages: - Hover on today's date * Verify message: "Cannot select: Date is in the past" - Hover on tomorrow (with 2-day lead period) * Verify message: "Cannot select: Insufficient lead time (2 days required before start)" - Hover on the day after tomorrow * Verify message: "Cannot select: Insufficient lead time (2 days required before start)" * Should NOT show "conflicts with existing booking" if no booking exists 6. Test existing booking conflict messages: - Hover over Jan 12 (part of existing booking) * Verify message: "Cannot select: This date is part of an existing booking" - Hover over Jan 8 (existing booking's lead period) * Verify message: "Cannot select: This date is part of an existing booking's lead period" - Hover over Jan 16 (existing booking's trail period) * Verify message: "Cannot select: This date is part of an existing booking's trail period" 7. Test lead/trail period conflict messages: - Try to select Jan 19-20 as booking dates (2-day lead = Jan 17-18) - Hover over Jan 19 when it appears disabled * Verify error message: "Cannot select: Lead period (2 days before start) conflicts with existing booking's trail period" 8. Test info messages for valid dates: - Hover over Jan 21 (no conflicts, with lead period configured) * Verify info message: "Selecting start date. Lead period: 2 days before start" - Configure booking with NO lead period (0 or blank) - Hover over a valid date * Verify message: "Selecting start date" (no mention of lead period) 9. Test multiple conflict messages: - Position calendar to hover between two bookings where both lead and trail conflict * Verify message shows both conflicts separated by semicolon * Example: "Cannot select: lead period conflicts with existing booking's trail period; trail period conflicts with existing booking's lead period" 10. Verify all feedback messages: - Are properly translated (check .po files if applicable) - Use consistent "lead period" and "trail period" terminology - Are clear and helpful for librarians - Update color coding (red for errors, blue for info)
Created attachment 191354 [details] [review] Bug 37707: Fix timezone handling in place_booking modal This patch fixes timezone inconsistencies in the place_booking modal that caused dates to shift when the server and browser are in different timezones. Issues Fixed: 1. Date index creation used .toISOString().split("T")[0] which converted to UTC, causing western timezone dates to appear on wrong calendar days 2. Date comparisons mixed flatpickr.parseDate() and dayjs() without normalizing to start-of-day 3. Booking overlap detection had inconsistent timezone handling Changes: - Replace .toISOString().split("T")[0] with dayjs().format('YYYY-MM-DD') to maintain browser timezone consistency - Normalize all date comparisons to start-of-day using dayjs().startOf('day') - Use dayjs() consistently for parsing RFC3339 datetime strings from API - Add explicit .startOf('day') and .endOf('day') for API submission clarity These changes ensure: - Bookings display on correct calendar days regardless of browser timezone - Multi-day bookings span the correct number of days - Conflict detection works consistently across all timezones - Item availability calculations are accurate - Future hourly booking support is preserved (time components maintained) Test plan: 1. Set browser to PST (UTC-8), server to UTC 2. Create a booking for January 15 3. Verify booking displays on Jan 15 only (not Jan 15-16) 4. Create a 3-day booking (Jan 15-17) 5. Verify displays on exactly 3 days 6. Test conflict detection with overlapping bookings 7. Repeat tests with browser in HST (UTC-10) and NZDT (UTC+13)
Created attachment 191355 [details] [review] Bug 37707: Add Cypress tests for timezone handling in place_booking modal This patch adds comprehensive timezone tests to validate that the place_booking modal handles dates correctly regardless of browser timezone differences from the server. Test Coverage: 1. Date Index Creation Consistency - Validates bookings display on correct calendar dates - Tests the dayjs().format('YYYY-MM-DD') fix 2. Multi-Day Booking Span - Ensures 3-day bookings span exactly 3 days - Prevents UTC conversion from adding extra days 3. Date Comparison Consistency - Verifies conflict detection works across timezones - Tests normalized start-of-day comparisons 4. API Submission Round-Trip - Validates dates survive browser → API → database flow - Checks RFC3339 handling and timezone offset preservation 5. Cross-Month Boundary - Tests bookings spanning month boundaries - Validates no date shifts at month transitions These tests validate the timezone fixes in place_booking.js and ensure bookings work correctly for users in any timezone. Test plan: Run inside KTD container: docker exec --user kohadev-koha --workdir /kohadevbox/koha -i \ kohadev-koha-1 bash -c 'npx cypress run --spec \ "t/cypress/integration/Circulation/bookingsModalTimezone_spec.ts"' Expected result: All 5 tests should pass
Created attachment 191356 [details] [review] Bug 37707: Add Cypress tests for bidirectional lead/trail period conflicts This enhances the bookings lead/trail period tests to validate that: - New booking's lead period respects existing bookings' trail periods - New booking's trail period respects existing bookings' lead periods Previously, we only checked: - New booking lead vs existing booking actual dates - New booking trail vs existing booking actual dates Now we also validate the full "protected period" concept where each existing booking reserves: lead + actual + trail period. Test timeline updated: - Booking A: Days 20-25 (protected: 18-28) - Booking B: Days 60-65 (protected: 58-68) New test coverage: - TEST 2B: New lead conflicts with existing trail (Days 27-30) - TEST 6B: New trail conflicts with existing lead (Days 55-56) - TEST 7: Valid booking window (Days 31-54) respecting both Current status: Tests FAIL as expected, revealing the bug that bidirectional checking is not yet implemented.
Created attachment 191357 [details] [review] Bug 37707: Improve lead/trail period conflict detection This implements the full "protected period" concept for bookings, where each existing booking reserves: lead period + actual dates + trail period. Previously, we only checked: - New booking lead vs existing booking actual dates - New booking trail vs existing booking actual dates Now we ALSO check: - New booking lead vs existing booking trail periods - New booking trail vs existing booking lead periods This ensures librarians cannot create bookings too close together, respecting both item preparation time (lead) and processing time (trail). Test plan: 1. Apply all patches and run: yarn build 2. Configure a bookable item with 2-day lead and 3-day trail periods 3. Create booking A: January 5-9 - This reserves Jan 3-4 (lead), Jan 5-9 (actual), Jan 10-12 (trail) 4. Attempt to create booking B: January 12-15 with 2-day lead - Lead would be Jan 10-11, which conflicts with booking A's trail 5. Verify days 10-11 are visually disabled with striped pattern 6. Verify hovering shows "conflicts with existing booking's trail period" 7. Verify you cannot select January 12 as start date 8. Verify January 13 IS selectable (no conflict) 9. Run Cypress tests to confirm: npx cypress run --spec "t/cypress/integration/Circulation/bookingsModalDatePicker_spec.ts"
Created attachment 191358 [details] [review] Bug 37707: (follow-up) Add visual refinements for existing booking lead/trail periods This patch enhances the visual presentation of existing bookings' protected periods (lead/trail) to match the polished appearance of new booking lead/trail period indicators. Test plan: 1. Apply all patches and run: yarn build 2. Configure a bookable item with 2-day lead and 2-day trail 3. Create an existing booking for January 10-15 4. Open the booking calendar for that item 5. Verify visual styling of protected periods: - Jan 8-9 (lead period): diagonal striped pattern, rounded left edge on Jan 8 - Jan 10-15 (booking): solid color fill - Jan 16-17 (trail period): diagonal striped pattern, rounded right edge on Jan 17 6. Verify no visual gaps between consecutive protected period dates 7. Verify the striped pattern is clearly distinguishable from solid booking dates 8. Hover over different date ranges and verify lead/trail styling updates correctly
Created attachment 191359 [details] [review] Bug 37707: (follow-up) Add textual feedback for booking lead/trail period conflicts This patch adds a feedback message container below the calendar that provides contextual information about lead/trail period requirements and conflicts, improving accessibility and user understanding. The feedback updates dynamically on hover, showing: - Info messages when hovering selectable dates - Error messages when hovering dates disabled due to conflicts - Specific explanations distinguishing between conflict types (e.g., new lead vs existing trail, new trail vs existing lead) - Multiple conflict messages when both lead and trail periods conflict - Specific messages for past dates and insufficient lead time Key improvements: - Standardized terminology consistently uses "lead period" and "trail period" - Proper internationalization using __() for all user-facing strings - Structured conflict reason tracking using leadConflictReason/trailConflictReason objects - Fixed off-by-one errors in lead/trail period range calculations - Corrected boundary condition checks throughout (isSameOrBefore/isSameOrAfter) - Added safeguards for direct hovering on existing booking periods - Styling moved from inline JavaScript to SCSS using Bootstrap alert classes - Empty/zero periods are handled gracefully (not mentioned in messages) - Accurate conflict detection prioritizes what the hovered date IS over what it conflicts with This complements the visual color indicators by providing explicit textual explanations, improving accessibility and user understanding. Test plan: 1. Apply all patches and run: yarn build 2. Configure a bookable item with 2-day lead and 3-day trail periods 3. Create an existing booking for January 10-15 (protected: Jan 8-18) 4. Open the booking calendar and observe feedback area below calendar 5. Test past date and insufficient lead time messages: - Hover on today's date * Verify message: "Cannot select: Date is in the past" - Hover on tomorrow (with 2-day lead period) * Verify message: "Cannot select: Insufficient lead time (2 days required before start)" - Hover on the day after tomorrow * Verify message: "Cannot select: Insufficient lead time (2 days required before start)" * Should NOT show "conflicts with existing booking" if no booking exists 6. Test existing booking conflict messages: - Hover over Jan 12 (part of existing booking) * Verify message: "Cannot select: This date is part of an existing booking" - Hover over Jan 8 (existing booking's lead period) * Verify message: "Cannot select: This date is part of an existing booking's lead period" - Hover over Jan 16 (existing booking's trail period) * Verify message: "Cannot select: This date is part of an existing booking's trail period" 7. Test lead/trail period conflict messages: - Try to select Jan 19-20 as booking dates (2-day lead = Jan 17-18) - Hover over Jan 19 when it appears disabled * Verify error message: "Cannot select: Lead period (2 days before start) conflicts with existing booking's trail period" 8. Test info messages for valid dates: - Hover over Jan 21 (no conflicts, with lead period configured) * Verify info message: "Selecting start date. Lead period: 2 days before start" - Configure booking with NO lead period (0 or blank) - Hover over a valid date * Verify message: "Selecting start date" (no mention of lead period) 9. Test multiple conflict messages: - Position calendar to hover between two bookings where both lead and trail conflict * Verify message shows both conflicts separated by semicolon * Example: "Cannot select: lead period conflicts with existing booking's trail period; trail period conflicts with existing booking's lead period" 10. Verify all feedback messages: - Are properly translated (check .po files if applicable) - Use consistent "lead period" and "trail period" terminology - Are clear and helpful for librarians - Update color coding (red for errors, blue for info)
Created attachment 191360 [details] [review] Bug 37707: Fix timezone handling in place_booking modal This patch fixes timezone inconsistencies in the place_booking modal that caused dates to shift when the server and browser are in different timezones. Issues Fixed: 1. Date index creation used .toISOString().split("T")[0] which converted to UTC, causing western timezone dates to appear on wrong calendar days 2. Date comparisons mixed flatpickr.parseDate() and dayjs() without normalizing to start-of-day 3. Booking overlap detection had inconsistent timezone handling Changes: - Replace .toISOString().split("T")[0] with dayjs().format('YYYY-MM-DD') to maintain browser timezone consistency - Normalize all date comparisons to start-of-day using dayjs().startOf('day') - Use dayjs() consistently for parsing RFC3339 datetime strings from API - Add explicit .startOf('day') and .endOf('day') for API submission clarity These changes ensure: - Bookings display on correct calendar days regardless of browser timezone - Multi-day bookings span the correct number of days - Conflict detection works consistently across all timezones - Item availability calculations are accurate - Future hourly booking support is preserved (time components maintained) Test plan: 1. Set browser to PST (UTC-8), server to UTC 2. Create a booking for January 15 3. Verify booking displays on Jan 15 only (not Jan 15-16) 4. Create a 3-day booking (Jan 15-17) 5. Verify displays on exactly 3 days 6. Test conflict detection with overlapping bookings 7. Repeat tests with browser in HST (UTC-10) and NZDT (UTC+13)
Created attachment 191361 [details] [review] Bug 37707: Add Cypress tests for timezone handling in place_booking modal This patch adds comprehensive timezone tests to validate that the place_booking modal handles dates correctly regardless of browser timezone differences from the server. Test Coverage: 1. Date Index Creation Consistency - Validates bookings display on correct calendar dates - Tests the dayjs().format('YYYY-MM-DD') fix 2. Multi-Day Booking Span - Ensures 3-day bookings span exactly 3 days - Prevents UTC conversion from adding extra days 3. Date Comparison Consistency - Verifies conflict detection works across timezones - Tests normalized start-of-day comparisons 4. API Submission Round-Trip - Validates dates survive browser → API → database flow - Checks RFC3339 handling and timezone offset preservation 5. Cross-Month Boundary - Tests bookings spanning month boundaries - Validates no date shifts at month transitions These tests validate the timezone fixes in place_booking.js and ensure bookings work correctly for users in any timezone. Test plan: Run inside KTD container: docker exec --user kohadev-koha --workdir /kohadevbox/koha -i \ kohadev-koha-1 bash -c 'npx cypress run --spec \ "t/cypress/integration/Circulation/bookingsModalTimezone_spec.ts"' Expected result: All 5 tests should pass
OK.. I've fixed up the messages now and also reconsidered the timezone handling as there were clearly some gremlins crept back in. Should all be ready for another round of testing pretty please and thankyou.
Everything I did in the UI worked great! Messages clear and accurate. But I've got a failing Cypress test: 1) Booking Modal Date Picker Tests should handle date range validation correctly: AssertionError: Timed out retrying after 10000ms: expected '<span.flatpickr-day.leadDisable>' to have class 'selected' at cy.get.should.timeout (webpack://koha/./t/cypress/support/flatpickr.js:337:58)
I set my browser timezone for PST. As before, I did 2 days lead and 3 days trail. When setting a booking for Jan. 16 only (I could not use Jan. 15 with the 2 day lead, which is expected.) I noticed the following: 1. The start and end dates on the booking table for the bib record are 01/16/2026 and 01/17/2026. Shouldn't I see same start and end date there? 2. Trying to book a second booking, the lead and trail time looked to be enforced. I tried placing a second booking on 1/21, and got an error because the lead time would conflict with the 1st booking's trail time. Nice! I could place a booking beginning on 1/22, which would put booking B's lead time (1/20 and 1/21) out of conflict with Booking A's trail time (1/17, 1/18, 1/19). 3. Placing Booking B for dates 1/22-1/27 shows an end date in the table of 1/28 though (BookingEnddates.png) I am going to try working through the rest of the test plan bookings.
Created attachment 191394 [details] BookingEnddates.png
I've also noticed that for bookings on bibs with more than one item, the calendar is showing conflicts for the other items. For example, on bib 15, I have two bookings placed on item 39999000000672. When I go to place a booking on item 39999000000634, the calendar/date picker gives me the same errors as if I were trying to place a conflicting booking on 39999000000672. See 39999000000634Booking.png
Created attachment 191395 [details] 39999000000634Booking.png
I've gone through: Test plan: 1. Set browser to PST (UTC-8), server to UTC 2. Create a booking for January 15 3. Verify booking displays on Jan 15 only (not Jan 15-16) 4. Create a 3-day booking (Jan 15-17) 5. Verify displays on exactly 3 days 6. Test conflict detection with overlapping bookings 7. Repeat tests with browser in HST (UTC-10) and NZDT (UTC+13) -- I ran into trouble with NZT. The end date in the table was adding two days. For example, for a booking set on the calendar for 1/16-1/18, the table end date is reading 1/20/2026. In the date picker, the booking dates (not trail time) cover 1/16, 17, 18 and 19. The trail period goes through 1/22 instead of 1/21. To recap from before: -- for PST and HST, the date picker dates looked correct, but the end date in the table was always an extra day. -- When trying to book on another item from the same bib, the date picker calendar will show ineligible dates from bookings on another item. If I hard refreshed the page, the display in the date picker would reset, but this could be confusing to users. Let me know if I can look at anything else here.
Hi folks, started QA on this bug yesterday. Problem: implicit timezones - The timezone issues stem from the code being implicitly timezone-aware without declaring which timezone is authoritative. - When code uses .toISOString() or .toDate(), it performs timezone conversions as side effects rather than intentional operations. This works when browser and server timezones happen to match, but breaks otherwise. The QA failures demonstrate this: - PST browser: end date shifts +1 day - NZDT browser: end date shifts +2 days - The shift correlates directly with UTC offset Potential fix for this: the library timezone is authoritative I dug up some examples to check how other booking systems handle this, since they have the same problem: - Airbnb: Check-in/checkout times are in "local time" (property timezone)(www.airbnb.com/help/article/41) - Booking.com: "All timestamps returned by Booking.com's Demand API are in UTC... convert from UTC dynamically based on user or property location" and "Timing is based on the property's local timezone" (developers.booking.com/demand/docs/development-guide/code-conventions, developers.booking.com/connectivity/docs/reporting-api/b_xml-reporting) My understanding is that booking dates should be interpreted in the library's timezone, not the patron's. This makes sense because: - The item is physically (for common use cases right now) at the library - Pickup/return happens during library hours - Lead/trail periods align with library operations How I implemented this: - Form submission - Extract the DATE value the user selected (just YYYY-MM-DD), then send as explicit UTC boundaries using dayjs.utc() to ensure startOf/endOf operate in UTC, not browser timezone: dayjs.utc(startDate).startOf("day").toISOString() // "2026-01-20T00:00:00.000Z" dayjs.utc(endDate).endOf("day").toISOString() // "2026-01-20T23:59:59.999Z" - This preserves the date regardless of browser timezone. - Timeline display - Convert stored UTC back to library timezone using $timezone(), then use $toDisplayDate() helper to create Date objects that render consistently: const startServerTz = dayjs(data.start_date).tz($timezone()); start: $toDisplayDate(startServerTz) - This ensures staff see dates in library time, not their browser's time. - Conflict detection - All date comparisons normalized to start-of-day to avoid time-component interference. The fix works, but the timezone handling should be made more explicit: 1. UI indicator - Show "(Library time)" near the date picker so patrons in different timezones understand (conditionally, only show if needed due to tz differences) 2. API contract - Document that booking dates represent library-local days, stored as UTC 3. Future-proofing - When hourly bookings are added, the same principle applies: times are in library timezone, converted to UTC for storage This approach eliminates timezone bugs by design. I have a follow-up patch to validate the idea and to retest what surfaced in QA. What do we think?
Created attachment 191746 [details] [review] Bug 37707: (follow-up) Fix timezone handling for cross-timezone bookings This patch fixes timezone issues that caused booking dates to shift when the browser and server are in different timezones. The code used implicit timezone conversions via .toISOString() and .toDate(), which work when browser and server timezones match but fail otherwise. QA testing showed: - PST browser: end date shifts +1 day - NZDT browser: end date shifts +2 days Make timezone handling explicit by establishing that booking dates are interpreted in the library's timezone. - Form submission: Extract date value (YYYY-MM-DD) and send as explicit UTC day boundaries using dayjs.utc().startOf/endOf('day') - Timeline display: Convert UTC to library timezone using $timezone() and new $toDisplayDate() helper for consistent rendering - Added $timezone() to expose server timezone to JavaScript - Added $toDisplayDate() to create display-ready Date objects that render correctly regardless of browser timezone To test: 1. Apply patch and run: yarn build 2. Configure a bookable item with 2-day lead and 3-day trail periods Timezone handling (PST): 3. Set browser timezone to PST (America/Los_Angeles), for example with Chrome Devtools -> Ctrl/Cmd + Shift + P -> sensors -> Location 4. Create a single-day booking for Jan 20 5. Verify the booking table shows start: Jan 20, end: Jan 20 (not Jan 21) 6. Verify the timeline shows the booking on Jan 20 only 7. Create a 3-day booking (Jan 22-24) 8. Verify the table shows start: Jan 22, end: Jan 24 9. Verify the timeline spans exactly 3 days Timezone handling (NZDT): 10. Set browser timezone to NZDT (Pacific/Auckland) 11. Repeat steps 4-9 12. Verify dates do not shift by +2 days as previously reported Test lead/trail conflict detection: 13. With existing booking on Jan 20 (trail period: Jan 21-23) 14. Attempt to create new booking starting Jan 24 (lead: Jan 22-23) 15. Verify conflict is detected (lead overlaps with trail) 16. Verify booking starting Jan 26 (lead: Jan 24-25) is allowed Test multi-item filtering: 17. On a bib with multiple bookable items 18. Create booking on item A for Jan 20 19. Open booking modal, select item B 20. Verify calendar does NOT show conflicts from item A's booking
Created attachment 192006 [details] [review] Bug 37707: Add bidirectional lead/trail period conflict detection Enhance the booking modal to detect and prevent lead/trail period conflicts in both directions: - New booking's lead period vs existing booking's trail period - New booking's trail period vs existing booking's lead period Visual feedback: - Highlight existing booking's lead periods (before booking starts) - Highlight existing booking's trail periods (after booking ends) - Add CSS classes for start/end boundaries with rounded corners User feedback: - Show contextual messages explaining why dates are blocked - Differentiate between lead period, trail period, and booking conflicts - Display informational messages when hovering available dates The conflict detection uses mathematical date range comparisons that work across month boundaries, not just visible calendar dates.
Created attachment 192007 [details] [review] Bug 37707: (follow-up) Support lead/trail periods for 'any item' bookings When booking "any item of type X", lead/trail period handling must consider that multiple items may be available: - Track per-item conflicts instead of global conflicts - Only disable dates when ALL items of the type have conflicts - Find closest "all items booked" dates for visual feedback - Use mathematical search (180 days) to detect conflicts across month boundaries Visual feedback for 'any item' mode: - Show lead/trail periods around "all items booked" dates - These represent dates where no item of the type is available Skip redundant class-based conflict checks since mathematical detection already handles cross-month boundary cases.
Created attachment 192008 [details] [review] Bug 37707: (follow-up) Fix timezone handling for bookings Fix date handling issues that caused bookings to shift by a day when the browser timezone differs from the server timezone: - Normalize dates to browser timezone for calendar display - Use dayjs without UTC conversion for bookingsByDate keys - Extract local date and send as explicit UTC day boundaries - Preserve user's selected DATE regardless of browser timezone Timeline display: - Convert server dates to library timezone for display - Add $timezone() and $toDisplayDate() helper functions This ensures that a booking for "June 15" displays and saves as June 15 regardless of the user's timezone offset.
Created attachment 192009 [details] [review] Bug 37707: (follow-up) Refactor place_booking.js for maintainability Extract utility functions and reduce code duplication: - Add toInt(), startOfDay(), datesOverlap(), isDateInRange() helpers - Simplify containsAny() using Set and Array.some() - Refactor isItemAvailableForPeriod() to use new utilities - Refactor getAvailableItemsOnDate() and isDateDisabledForSpecificItem() - Extract submit handler helpers: getAvailableItemsForPeriod(), buildBookingPayload(), createTimelineItem(), showBookingError(), showBookingSuccess(), refreshBookingsTable(), setPickerDates() - Replace parseInt() calls with toInt() for consistency - Simplify modal reset handler with jQuery method chaining No functional changes - prepares codebase for future Vue conversion.
Created attachment 192010 [details] [review] Bug 37707: (follow-up) Add comprehensive Cypress tests for bookings modal Reorganize and expand Cypress tests into three focused spec files: bookingsModalBasic_spec.ts: - Modal initialization and field interactions - Form validation and submission - Edit booking functionality - 'Any item' booking with server-side item selection bookingsModalDatePicker_spec.ts: - Flatpickr initialization and constraints - Date range validation - Circulation rules (issue length, renewals) - Lead/trail period conflict detection - 'Any item' mode date availability - Event dots for existing bookings bookingsModalTimezone_spec.ts: - Cross-timezone date display - Multi-day booking spans - Conflict detection with timezone awareness - API round-trip date preservation - Month boundary handling Add shared test utilities to e2e.js for date helpers.
Created attachment 192800 [details] [review] Bug 37707: Add bidirectional lead/trail period conflict detection Enhance the booking modal to detect and prevent lead/trail period conflicts in both directions: - New booking's lead period vs existing booking's trail period - New booking's trail period vs existing booking's lead period Visual feedback: - Highlight existing booking's lead periods (before booking starts) - Highlight existing booking's trail periods (after booking ends) - Add CSS classes for start/end boundaries with rounded corners User feedback: - Show contextual messages explaining why dates are blocked - Differentiate between lead period, trail period, and booking conflicts - Display informational messages when hovering available dates The conflict detection uses mathematical date range comparisons that work across month boundaries, not just visible calendar dates. Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Created attachment 192801 [details] [review] Bug 37707: (follow-up) Support lead/trail periods for 'any item' bookings When booking "any item of type X", lead/trail period handling must consider that multiple items may be available: - Track per-item conflicts instead of global conflicts - Only disable dates when ALL items of the type have conflicts - Find closest "all items booked" dates for visual feedback - Use mathematical search (180 days) to detect conflicts across month boundaries Visual feedback for 'any item' mode: - Show lead/trail periods around "all items booked" dates - These represent dates where no item of the type is available Skip redundant class-based conflict checks since mathematical detection already handles cross-month boundary cases. Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Created attachment 192802 [details] [review] Bug 37707: (follow-up) Fix timezone handling for bookings Fix date handling issues that caused bookings to shift by a day when the browser timezone differs from the server timezone: - Normalize dates to browser timezone for calendar display - Use dayjs without UTC conversion for bookingsByDate keys - Extract local date and send as explicit UTC day boundaries - Preserve user's selected DATE regardless of browser timezone Timeline display: - Convert server dates to library timezone for display - Add $timezone() and $toDisplayDate() helper functions This ensures that a booking for "June 15" displays and saves as June 15 regardless of the user's timezone offset. Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Created attachment 192803 [details] [review] Bug 37707: (follow-up) Refactor place_booking.js for maintainability Extract utility functions and reduce code duplication: - Add toInt(), startOfDay(), datesOverlap(), isDateInRange() helpers - Simplify containsAny() using Set and Array.some() - Refactor isItemAvailableForPeriod() to use new utilities - Refactor getAvailableItemsOnDate() and isDateDisabledForSpecificItem() - Extract submit handler helpers: getAvailableItemsForPeriod(), buildBookingPayload(), createTimelineItem(), showBookingError(), showBookingSuccess(), refreshBookingsTable(), setPickerDates() - Replace parseInt() calls with toInt() for consistency - Simplify modal reset handler with jQuery method chaining No functional changes - prepares codebase for future Vue conversion. Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Created attachment 192804 [details] [review] Bug 37707: (follow-up) Add comprehensive Cypress tests for bookings modal Reorganize and expand Cypress tests into three focused spec files: bookingsModalBasic_spec.ts: - Modal initialization and field interactions - Form validation and submission - Edit booking functionality - 'Any item' booking with server-side item selection bookingsModalDatePicker_spec.ts: - Flatpickr initialization and constraints - Date range validation - Circulation rules (issue length, renewals) - Lead/trail period conflict detection - 'Any item' mode date availability - Event dots for existing bookings bookingsModalTimezone_spec.ts: - Cross-timezone date display - Multi-day booking spans - Conflict detection with timezone awareness - API round-trip date preservation - Month boundary handling Add shared test utilities to e2e.js for date helpers. Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Created attachment 192805 [details] [review] Bug 37707: (QA follow-up) Fix typo in comment Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Created attachment 192806 [details] [review] Bug 37707: (QA follow-up) Fix grammatical error Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Created attachment 192807 [details] [review] Bug 37707: (QA follow-up) Fix incorrect bold date expectations in Cypress test - The test for circulation rules date calculations did not account for the start date being bold, only the period endpoint dates - place_booking.js explicitly adds the selected start date to boldDates (boldDates = [new Date(startDate)]), giving it the "title" class - The verification loop checking for unexpected bold dates then failed when it encountered the start date, which was bold but not expected - Add clearZoneStart to expectedBoldDates to match actual behavior To test: - yarn cypress run --spec t/cypress/integration/Circulation/bookingsModalDatePicker_spec.ts - Verify that the "should handle circulation rules date calculations and visual feedback" test now passes Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Created attachment 192863 [details] [review] Bug 37707: Add bidirectional lead/trail period conflict detection Enhance the booking modal to detect and prevent lead/trail period conflicts in both directions: - New booking's lead period vs existing booking's trail period - New booking's trail period vs existing booking's lead period Visual feedback: - Highlight existing booking's lead periods (before booking starts) - Highlight existing booking's trail periods (after booking ends) - Add CSS classes for start/end boundaries with rounded corners User feedback: - Show contextual messages explaining why dates are blocked - Differentiate between lead period, trail period, and booking conflicts - Display informational messages when hovering available dates The conflict detection uses mathematical date range comparisons that work across month boundaries, not just visible calendar dates. Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de> Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Created attachment 192864 [details] [review] Bug 37707: (follow-up) Support lead/trail periods for 'any item' bookings When booking "any item of type X", lead/trail period handling must consider that multiple items may be available: - Track per-item conflicts instead of global conflicts - Only disable dates when ALL items of the type have conflicts - Find closest "all items booked" dates for visual feedback - Use mathematical search (180 days) to detect conflicts across month boundaries Visual feedback for 'any item' mode: - Show lead/trail periods around "all items booked" dates - These represent dates where no item of the type is available Skip redundant class-based conflict checks since mathematical detection already handles cross-month boundary cases. Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de> Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Created attachment 192865 [details] [review] Bug 37707: (follow-up) Fix timezone handling for bookings Fix date handling issues that caused bookings to shift by a day when the browser timezone differs from the server timezone: - Normalize dates to browser timezone for calendar display - Use dayjs without UTC conversion for bookingsByDate keys - Extract local date and send as explicit UTC day boundaries - Preserve user's selected DATE regardless of browser timezone Timeline display: - Convert server dates to library timezone for display - Add $timezone() and $toDisplayDate() helper functions This ensures that a booking for "June 15" displays and saves as June 15 regardless of the user's timezone offset. Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de> Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Created attachment 192866 [details] [review] Bug 37707: (follow-up) Refactor place_booking.js for maintainability Extract utility functions and reduce code duplication: - Add toInt(), startOfDay(), datesOverlap(), isDateInRange() helpers - Simplify containsAny() using Set and Array.some() - Refactor isItemAvailableForPeriod() to use new utilities - Refactor getAvailableItemsOnDate() and isDateDisabledForSpecificItem() - Extract submit handler helpers: getAvailableItemsForPeriod(), buildBookingPayload(), createTimelineItem(), showBookingError(), showBookingSuccess(), refreshBookingsTable(), setPickerDates() - Replace parseInt() calls with toInt() for consistency - Simplify modal reset handler with jQuery method chaining No functional changes - prepares codebase for future Vue conversion. Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de> Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Created attachment 192867 [details] [review] Bug 37707: (follow-up) Add comprehensive Cypress tests for bookings modal Reorganize and expand Cypress tests into three focused spec files: bookingsModalBasic_spec.ts: - Modal initialization and field interactions - Form validation and submission - Edit booking functionality - 'Any item' booking with server-side item selection bookingsModalDatePicker_spec.ts: - Flatpickr initialization and constraints - Date range validation - Circulation rules (issue length, renewals) - Lead/trail period conflict detection - 'Any item' mode date availability - Event dots for existing bookings bookingsModalTimezone_spec.ts: - Cross-timezone date display - Multi-day booking spans - Conflict detection with timezone awareness - API round-trip date preservation - Month boundary handling Add shared test utilities to e2e.js for date helpers. Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de> Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Created attachment 192868 [details] [review] Bug 37707: (QA follow-up) Fix typo in comment Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de> Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Created attachment 192869 [details] [review] Bug 37707: (QA follow-up) Fix grammatical error Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de> Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Created attachment 192870 [details] [review] Bug 37707: (QA follow-up) Fix incorrect bold date expectations in Cypress test - The test for circulation rules date calculations did not account for the start date being bold, only the period endpoint dates - place_booking.js explicitly adds the selected start date to boldDates (boldDates = [new Date(startDate)]), giving it the "title" class - The verification loop checking for unexpected bold dates then failed when it encountered the start date, which was bold but not expected - Add clearZoneStart to expectedBoldDates to match actual behavior To test: - yarn cypress run --spec t/cypress/integration/Circulation/bookingsModalDatePicker_spec.ts - Verify that the "should handle circulation rules date calculations and visual feedback" test now passes Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de> Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Nice work everyone! Pushed to main for 26.05