@@ -24,40 +24,69 @@ def get_reservables(typ):
2424 return q .QuerySql ("""
2525 SELECT ReservableId,
2626 ParentId,
27- BadgeColor as Color,
27+ COALESCE( BadgeColor, '#153aa8') as Color,
2828 Name,
2929 Description,
3030 IsReservable,
3131 IsEnabled,
3232 IsCountable,
3333 Quantity
3434 FROM Reservable
35- WHERE ReservableTypeId = 1
35+ WHERE 1=1
36+ -- AND ReservableTypeId = 1
3637 AND IsDeleted = 0
3738 AND IsEnabled = 1
39+
40+ ORDER BY ReservableTypeId, Name
3841 ;
3942""" )
4043
4144
4245def get_reservations (typ , dt ):
4346 return q .QuerySql ("""
47+ -- Room things
4448 SELECT
4549 rb.ReservableId,
4650 rv.MeetingStart,
4751 COALESCE(rv.MeetingEnd, rv.MeetingStart) as MeetingEnd,
4852 COALESCE(NULLIF(rv.SetupMinutes, ''), 0) as SetupMinutes,
4953 COALESCE(NULLIF(rv.SetupMinutes, ''), 0) as TeardownMinutes,
5054 COALESCE(NULLIF(m.Description, ''), o.OrganizationName) as Name,
51- m.MeetingId
55+ 0 as Quantity,
56+ m.MeetingId,
57+ o.LeaderName
58+ INTO #reservables
5259 FROM Reservations rv
5360 JOIN Reservable rb ON rv.ReservableId = rb.ReservableId
5461 JOIN Meetings m ON rv.MeetingId = m.MeetingId
5562 JOIN Organizations o ON m.OrganizationId = o.OrganizationId
63+ WHERE rv.MeetingId IS NOT NULL
64+ AND rv.MeetingEnd > '{0}'
65+ AND rv.MeetingStart < DATEADD(day, 1, '{0}');
66+
67+ -- Returns reservable items (furniture and services, not reservables)
68+ SELECT
69+ ri.ReservableId,
70+ rv.MeetingStart,
71+ COALESCE(rv.MeetingEnd, rv.MeetingStart) as MeetingEnd,
72+ COALESCE(NULLIF(rv.SetupMinutes, ''), 0) as SetupMinutes,
73+ COALESCE(NULLIF(rv.SetupMinutes, ''), 0) as TeardownMinutes,
74+ COALESCE(NULLIF(m.Description, ''), o.OrganizationName) as Name,
75+ ri.Quantity,
76+ m.MeetingId,
77+ o.LeaderName
78+ INTO #Jawns
79+ FROM ReservationItems ri
80+ LEFT JOIN Reservations rv ON ri.ReservationId = rv.ReservationId
81+ JOIN Reservable rb ON ri.ReservableId = rb.ReservableId
82+ JOIN Meetings m ON rv.MeetingId = m.MeetingId
83+ JOIN Organizations o ON m.OrganizationId = o.OrganizationId
5684 WHERE rv.MeetingId IS NOT NULL
5785 AND rv.MeetingEnd > '{0}'
5886 AND rv.MeetingStart < DATEADD(day, 1, '{0}')
59- ORDER BY rb.ReservableId, rv.MeetingStart
6087 ;
88+
89+ SELECT * FROM #reservables UNION SELECT * FROM #Jawns;
6190""" .format (dt ))
6291
6392def generate_calendar_html (date ):
@@ -115,7 +144,7 @@ def generate_calendar_html(date):
115144 html .append ("<strong>Month</strong>" )
116145 html .append (" | <a href='?v=w&%s'>Week</a>" % (curr_link ))
117146 html .append (" | <a href='?v=d&%s'>Day</a>" % (curr_link ))
118- html .append (" | <a href='?v=r&%s'>Rooms </a>" % (curr_link ))
147+ html .append (" | <a href='?v=r&%s'>Reservables </a>" % (curr_link ))
119148 html .append ("</div>" )
120149 html .append ("</div>" )
121150
@@ -234,7 +263,7 @@ def generate_calendar_vert_html(start_date, dayCount):
234263 else :
235264 html .append (" | <a href='?v=d&%s'>Day</a>" % (curr_link ))
236265
237- html .append (" | <a href='?v=r&%s'>Rooms </a>" % (curr_link ))
266+ html .append (" | <a href='?v=r&%s'>Reservables </a>" % (curr_link ))
238267
239268 html .append ("</div>" )
240269
@@ -320,19 +349,17 @@ def generate_calendar_vert_html(start_date, dayCount):
320349
321350 return "\n " .join (html )
322351
323-
324-
325352def generate_room_gantt_html (date ):
326- rooms = get_reservables ("r" )
353+ reservables = get_reservables ("r" )
327354 reservations = get_reservations ("r" , date )
328355
329356 hour_width = 6 # vw per hour
330357 total_hours = 25
331358
332- room_dict = {r .ReservableId : r for r in rooms }
333- children = {r .ReservableId : [] for r in rooms }
334- for r in rooms :
335- if r .ParentId in room_dict :
359+ reservable_dict = {r .ReservableId : r for r in reservables }
360+ children = {r .ReservableId : [] for r in reservables }
361+ for r in reservables :
362+ if r .ParentId in reservable_dict :
336363 children [r .ParentId ].append (r )
337364
338365 def time_to_vw (dt ):
@@ -356,7 +383,8 @@ def time_to_vw(dt):
356383 html .append (".gantt-container { overflow-x: scroll; flex: 1; position: relative; height: fit-content; }" )
357384 html .append (".gantt-chart { position: relative; width: %dvw; }" % (hour_width * (total_hours - 1 )))
358385 html .append (".room-row { position: relative; height: 2em; border-bottom: 1px solid #ccc; }" )
359- html .append (".bar { position: absolute; top: 2px; bottom: 2px; border-radius: 3px; color: #fff; padding: 2px; font-size: 0.8em; overflow: hidden; white-space: nowrap; }" )
386+ html .append (".bar { position: absolute; border-radius: 3px; color: #fff; padding: 2px; font-size: 0.8em; overflow: hidden; white-space: nowrap; line-height:.8em; }" )
387+ html .append (".bar small { opacity:.75; }" )
360388 html .append (".setup { opacity: 0.5; }" )
361389 html .append (".timegrid { position: absolute; top: 0; height: 100%; border-left: 1px dashed #ccc; font-size: 0.7em; color: #666; text-align: center; }" )
362390
@@ -381,7 +409,7 @@ def time_to_vw(dt):
381409 html .append ("<a href='?%s'>Month</a>" % (curr_link ))
382410 html .append (" | <a href='?v=w&%s'>Week</a>" % (curr_link ))
383411 html .append (" | <a href='?v=d&%s'>Day</a>" % (curr_link ))
384- html .append (" | <strong>Rooms </strong>" )
412+ html .append (" | <strong>Reservables </strong>" )
385413 html .append ("</div>" )
386414 html .append ("</div>" )
387415
@@ -391,24 +419,45 @@ def time_to_vw(dt):
391419
392420 html .append ("<div class='gantt-wrapper'>" )
393421
394- def room_has_reservations (room ):
395- if len ([r for r in reservations if r .ReservableId == room .ReservableId ]) > 0 :
422+
423+ def assign_lanes (reservations ):
424+ lanes = []
425+ for res in reservations :
426+ placed = False
427+ for lane in lanes :
428+ if all (res .MeetingStart >= r .MeetingEnd or res .MeetingEnd <= r .MeetingStart for r in lane ):
429+ lane .append (res )
430+ placed = True
431+ break
432+ if not placed :
433+ lanes .append ([res ])
434+ lane_map = {}
435+ for i , lane in enumerate (lanes ):
436+ for res in lane :
437+ lane_map [res ] = i
438+ return lane_map , max (1 , len (lanes ))
439+
440+
441+ def reservable_has_reservations (rbl ):
442+ if len (rbl ._reservations ) > 0 :
396443 return True
397444
398- for child in children .get (room .ReservableId , []):
399- if room_has_reservations (child ):
445+ for child in children .get (rbl .ReservableId , []):
446+ if reservable_has_reservations (child ):
400447 return True
401448
402449 return False
403450
404451
405452 # Room rows and bars
406- def render_room_rows ( room ):
407- if not room_has_reservations ( room ):
453+ def render_row ( rbl ):
454+ if not reservable_has_reservations ( rbl ):
408455 return
409456
410- html .append ("<div class='room-row'>" )
411- for res in [r for r in reservations if r .ReservableId == room .ReservableId ]:
457+ row_height = rbl ._lanes [1 ] * 2
458+
459+ html .append ("<div class='room-row' style='height:%dem'>" % (row_height ))
460+ for res in rbl ._reservations :
412461 start = res .MeetingStart
413462 end = res .MeetingEnd
414463 setup_start = start .AddMinutes (- res .SetupMinutes )
@@ -419,36 +468,60 @@ def render_room_rows(room):
419468 setup_left = time_to_vw (setup_start )
420469 setup_width = time_to_vw (teardown_end ) - setup_left
421470
422- color = room_dict [res .ReservableId ].Color
471+ color = reservable_dict [res .ReservableId ].Color
423472
424473 html .append ("<a href='/Meeting/MeetingDetails/%s'>" % res .MeetingId )
474+
475+
476+ lane = rbl ._lanes [0 ][res ]
477+ top_offset = round (lane / (.01 * rbl ._lanes [1 ]), 2 )
478+ bot_offset = round (((rbl ._lanes [1 ] - 1 - lane ) / (.01 * rbl ._lanes [1 ])), 2 )
425479
426480 if res .SetupMinutes > 0 or res .TeardownMinutes > 0 :
427- html .append ("<div class='bar setup' style='left:%.2fvw; width:%.2fvw; background:%s;'></div>" % (
428- setup_left , setup_width , color
481+ html .append ("<div class='bar setup' style='left:%.2fvw; width:%.2fvw; background:%s; top:calc(%.2f%% + 1px); bottom:calc(%.2f%% + 1px); '></div>" % (
482+ setup_left , setup_width , color , top_offset , bot_offset
429483 ))
430484
431- html .append ("<div class='bar' style='left:%.2fvw; width:%.2fvw; background:%s;' title=\" %s\" >%s</div> " % (
432- left , width , color , res .Name , res .Name
485+ html .append ("<div class='bar' style='left:%.2fvw; width:%.2fvw; background:%s; top:calc(%.2f%% + 1px); bottom:calc(%.2f%% + 1px); ' title=\" %s\" >%s" % (
486+ left , width , color , top_offset , bot_offset , res .Name , res .Name
433487 ))
488+ label = ""
489+ if res .Quantity > 0 :
490+ label = "(%d) " % (res .Quantity )
491+ if res .LeaderName is not None :
492+ label = "%s%s" % (label , res .LeaderName )
493+ if label != "" :
494+ html .append ("<small><br />%s</small>" % (label ))
495+ html .append ("</div>" )
434496 html .append ("</a>" )
435497 html .append ("</div>" )
436- for child in children .get (room .ReservableId , []):
437- render_room_rows (child )
498+
499+ for child in children .get (rbl .ReservableId , []):
500+ render_row (child )
501+
502+
503+ for rbl in reservables :
504+ rbl ._reservations = [r for r in reservations if r .ReservableId == rbl .ReservableId ]
505+ rbl ._lanes = assign_lanes (rbl ._reservations )
438506
439507 # Static room labels
440508 html .append ("<div class='room-labels'>" )
441- def render_room_labels (room , depth = 0 ):
442- if not room_has_reservations (room ):
509+
510+ def render_labels (rbl , depth = 0 ):
511+ if not reservable_has_reservations (rbl ):
443512 return
444513
445514 indent = " " * (depth * 4 )
446- html .append ("<div class='room-label'>%s%s</div>" % (indent , room .Name ))
447- for child in children .get (room .ReservableId , []):
448- render_room_labels (child , depth + 1 )
449- for room in rooms :
450- if room .ParentId not in room_dict :
451- render_room_labels (room )
515+ height = rbl ._lanes [1 ] * 2
516+ html .append ("<div class='room-label' style='height:%dem;'>%s%s</div>" % (height , indent , rbl .Name ))
517+ for child in children .get (rbl .ReservableId , []):
518+ render_labels (child , depth + 1 )
519+
520+
521+ for rbl in reservables :
522+ if rbl .ParentId not in reservable_dict :
523+ render_labels (rbl )
524+
452525 html .append ("</div>" )
453526
454527 # Scrollable Gantt chart
@@ -467,9 +540,9 @@ def render_room_labels(room, depth=0):
467540 half_left = left + hour_width / 2
468541 html .append ("<div class='timegrid' style='left:%.2fvw; width:0; border-left: 1px dashed #ccc;'></div>" % half_left )
469542
470- for room in rooms :
471- if room .ParentId not in room_dict :
472- render_room_rows (room )
543+ for room in reservables :
544+ if room .ParentId not in reservable_dict :
545+ render_row (room )
473546
474547 html .append ("</div></div>" ) # end gantt-chart and container
475548 html .append ("</div>" ) # end gantt-wrapper
0 commit comments