diff --git a/chrono/manager/static/css/style.scss b/chrono/manager/static/css/style.scss
index 9928db6e..678aee82 100644
--- a/chrono/manager/static/css/style.scss
+++ b/chrono/manager/static/css/style.scss
@@ -870,20 +870,73 @@ div#main-content.partial-booking-dayview {
background-color: var(--red);
z-index: 3;
}
-}
-.agenda-table.partial-bookings .booking {
- height: 70%;
- width: 100%;
- position: absolute;
- right: 0;
- top: 15%;
- background: #1066bc;
- &.present {
- background: hsl(120, 57%, 35%);
- }
- &.absent {
- background: hsl(355, 80%, 45%);
+ // Month view, table element
+ &-month {
+ width: 100%;
+ border-spacing: 0;
+ & col.we {
+ background-color: var(--zebra-color);
+ }
+ & col.today {
+ background-image: linear-gradient(
+ 135deg,
+ hsl(65, 65%, 94%) 20%,
+ hsl(65, 55%, 92%) 70%,
+ hsl(65, 50%, 90%) 90%);
+ }
+ &--day {
+ padding: .33em;
+ a {
+ color: var(--font-color);
+ font-weight: normal;
+ text-decoration: none;
+ }
+ &.today a {
+ font-weight: bold;
+ }
+ }
+ & .registrant {
+ &--name {
+ box-sizing: border-box;
+ text-align: right;
+ padding: .66rem;
+ font-size: 130%;
+ color: #505050;
+ font-weight: normal;
+ width: var(--registrant-name-width);
+ }
+ &--day-cell {
+ border-left: var(--separator-size) solid var(--separator-color);
+ text-align: center;
+ vertical-align: middle;
+ padding: .33em;
+ line-height: 0;
+ & .booking {
+ display: inline-block;
+ width: Min(100%, 1.75em);
+ height: 1.75em;
+ --booking-color: #1066bc;
+ background-color: var(--booking-color);
+ &.present {
+ background: var(--green);
+ }
+ &.absent {
+ background: var(--red);
+ }
+ }
+ }
+ }
+ &--registrant:nth-child(odd) {
+ & th, & td {
+ background-color: var(--zebra-color);
+ }
+ }
+ &--registrant:nth-child(even) {
+ & th, & td {
+ --separator-color: var(--zebra-color);
+ }
+ }
}
}
diff --git a/chrono/manager/templates/chrono/manager_partial_bookings_month_view.html b/chrono/manager/templates/chrono/manager_partial_bookings_month_view.html
index 728c27f4..4c103ce6 100644
--- a/chrono/manager/templates/chrono/manager_partial_bookings_month_view.html
+++ b/chrono/manager/templates/chrono/manager_partial_bookings_month_view.html
@@ -3,33 +3,54 @@
{% block content %}
-
-
-
-
- |
+
+
+
+
{% for day in days %}
-
- {{ day|date:"d" }}
- |
+
{% endfor %}
-
-
+
-
- {% for booking_info in user_booking_info %}
-
- {{ booking_info.user_name }} |
- {% for booking in booking_info.bookings %}
-
- {% if booking %}
-
- {% endif %}
- |
+
+
+ |
+ {% for day in days %}
+
+
+
+
+ |
{% endfor %}
- {% endfor %}
-
+
-
+
+ {% for booking_info in user_booking_info %}
+
+ {{ booking_info.user_name }} |
+ {% for booking in booking_info.bookings %}
+
+ {% if booking %}
+ {% if booking.check_css_class == 'present' %}
+ {% trans "Present" as booking_status %}
+ {% elif booking.check_css_class == 'absent' %}
+ {% trans "Absent" as booking_status %}
+ {% else %}
+ {% trans "Not checked" as booking_status %}
+ {% endif %}
+
+ {{ booking_status }}
+
+ {% endif %}
+ |
+ {% endfor %}
+
+ {% endfor %}
+
+
+
+
{% endblock %}
diff --git a/chrono/manager/views.py b/chrono/manager/views.py
index ccf50490..eaa319fa 100644
--- a/chrono/manager/views.py
+++ b/chrono/manager/views.py
@@ -2268,6 +2268,7 @@ class AgendaWeekMonthMixin:
self.first_day + datetime.timedelta(days=i)
for i in range((first_day_next_month - self.first_day).days)
]
+ context['today'] = localtime().date()
booking_info_by_user = {}
bookings = Booking.objects.filter(event__in=self.events).prefetch_related('user_checks')
diff --git a/tests/manager/test_partial_bookings.py b/tests/manager/test_partial_bookings.py
index b8216f10..076c6e81 100644
--- a/tests/manager/test_partial_bookings.py
+++ b/tests/manager/test_partial_bookings.py
@@ -1138,7 +1138,7 @@ def test_manager_partial_bookings_month_view(app, admin_user, freezer):
today = start_datetime.date()
resp = app.get('/manage/agendas/%s/month/%d/%d/%d/' % (agenda.pk, today.year, today.month, today.day))
- assert [int(x.text) for x in resp.pyquery('thead th a')] == list(range(1, 32))
+ assert [int(x.text) for x in resp.pyquery('thead th time')] == list(range(1, 32))
assert [x.text for x in resp.pyquery('tbody tr th')] == [
'User Absent',
@@ -1151,21 +1151,24 @@ def test_manager_partial_bookings_month_view(app, admin_user, freezer):
user_absent_row = resp.pyquery('tbody tr')[0]
assert len(resp.pyquery(user_absent_row)('td')) == 31
- assert len(resp.pyquery(user_absent_row)('td span')) == 1
+ assert len(resp.pyquery(user_absent_row)('td span.booking')) == 1
assert len(resp.pyquery(user_absent_row)('td span.booking.absent')) == 1
+ assert resp.pyquery(user_absent_row)('td span.booking.absent').text() == 'Absent'
subscription_not_booked_row = resp.pyquery('tbody tr')[1]
assert len(resp.pyquery(subscription_not_booked_row)('td')) == 31
- assert len(resp.pyquery(subscription_not_booked_row)('td span')) == 0
+ assert len(resp.pyquery(subscription_not_booked_row)('td span.booking')) == 0
user_not_checked_row = resp.pyquery('tbody tr')[2]
assert len(resp.pyquery(user_not_checked_row)('td')) == 31
assert len(resp.pyquery(user_not_checked_row)('td span.booking')) == 2
+ assert resp.pyquery(user_not_checked_row)('td span.booking').text() == 'Not checked Not checked'
user_present_row = resp.pyquery('tbody tr')[3]
assert len(resp.pyquery(user_present_row)('td')) == 31
- assert len(resp.pyquery(user_present_row)('td span')) == 1
+ assert len(resp.pyquery(user_present_row)('td span.booking')) == 1
assert len(resp.pyquery(user_present_row)('td span.booking.present')) == 1
+ assert resp.pyquery(user_present_row)('td span.booking.present').text() == 'Present'
user_present_mixed_row = resp.pyquery('tbody tr')[4]
assert len(resp.pyquery(user_present_mixed_row)('td')) == 31
@@ -1178,10 +1181,20 @@ def test_manager_partial_bookings_month_view(app, admin_user, freezer):
assert len(resp.pyquery(user_present_incomplete_row)('td span.booking.present')) == 0
resp = resp.click('Next month')
- assert [int(x.text) for x in resp.pyquery('thead th a')] == list(range(1, 31))
+ assert [int(x.text) for x in resp.pyquery('thead th time')] == list(range(1, 31))
assert [x.text for x in resp.pyquery('tbody tr th')] == ['Subscription Next Month']
assert len(resp.pyquery('tbody tr td')) == 30
+ freezer.move_to('2023-05-10 14:00')
+ resp = app.get(resp.request.url)
+ assert len(resp.pyquery('th.today')) == 0
+ assert len(resp.pyquery('col.today')) == 0
+
+ freezer.move_to('2023-06-10 14:00')
+ resp = app.get(resp.request.url)
+ assert resp.pyquery('th.today').text() == '10'
+ assert len(resp.pyquery('col.today')) == 1
+
def test_manager_partial_bookings_occupation_rates(app, admin_user):
agenda = Agenda.objects.create(label='Foo bar', kind='events', partial_bookings=True)