manager: display placeholder for leased bookings (#82774)

This commit is contained in:
Benjamin Dauvergne 2023-11-21 16:02:32 +01:00
parent 14b7de35cc
commit 2831272e56
8 changed files with 122 additions and 26 deletions

View File

@ -201,6 +201,18 @@ table.agenda-table {
text-align: center;
}
&.booking {
&.lease {
background:
repeating-linear-gradient(
135deg,
hsla(10, 10%, 75%, 0.7) 0,
hsla(10, 10%, 80%, 0.55) 10px,
transparent 11px,
transparent 20px);
// color: currentColor;
color: hsla(0, 0%, 0%, 0.7);
}
left: 0;
color: hsl(210, 84%, 40%);
padding: 1ex;
@ -562,6 +574,18 @@ div.agenda-settings .pk-tabs--container {
#event_details {
margin: 1em 0;
.objects-list .lease {
background:
repeating-linear-gradient(
135deg,
hsla(10, 10%, 75%, 0.7) 0,
hsla(10, 10%, 80%, 0.55) 10px,
transparent 11px,
transparent 20px);
}
.objects-list .lease span {
padding: 0 0.5ex 0 2ex;
}
}
@media print {

View File

@ -28,12 +28,16 @@
<ul class="objects-list single-links">
{% for booking in booked %}
<li>
<a {% if booking.get_backoffice_url %}href="{{ booking.get_backoffice_url }}"{% endif %}>{{ booking.get_user_block }}, {{ booking.creation_datetime|date:"DATETIME_FORMAT" }}</a>
{% if not booking.primary_booking %}
<a rel="popup" class="delete" href="{% url 'chrono-manager-booking-cancel' pk=agenda.id booking_pk=booking.id %}?next={{ request.path }}">{% trans "Cancel" %}</a>
<li{% if booking.lease %} class="lease"{% endif %}>
{% if booking.lease %}
<span>{% trans "Currently being booked..." %}</span>
{% else %}
<a class="delete disabled" title="{% trans "Can not cancel a secondary booking" %}" href="#">{% trans "Cancel" %}</a>
<a {% if booking.get_backoffice_url %}href="{{ booking.get_backoffice_url }}"{% endif %}>{{ booking.get_user_block }}, {{ booking.creation_datetime|date:"DATETIME_FORMAT" }}</a>
{% if not booking.primary_booking %}
<a rel="popup" class="delete" href="{% url 'chrono-manager-booking-cancel' pk=agenda.id booking_pk=booking.id %}?next={{ request.path }}">{% trans "Cancel" %}</a>
{% else %}
<a class="delete disabled" title="{% trans "Can not cancel a secondary booking" %}" href="#">{% trans "Cancel" %}</a>
{% endif %}
{% endif %}
</li>
{% endfor %}
@ -53,7 +57,7 @@
<div>
<ul class="objects-list single-links">
{% for booking in waiting %}
<li><a {% if booking.get_backoffice_url %}href="{{ booking.get_backoffice_url }}"{% endif %}>{{ booking.get_user_block }}, {{ booking.creation_datetime|date:"DATETIME_FORMAT" }}</a></li>
<li{% if booking.lease %} class="lease"{% endif %}><a {% if booking.get_backoffice_url %}href="{{ booking.get_backoffice_url }}"{% endif %}>{% if booking.lease %}{% trans "Currently being booked..." %}{% else %}{{ booking.get_user_block }}, {{ booking.creation_datetime|date:"DATETIME_FORMAT" }}{% endif %}</a></li>
{% endfor %}
</ul>
</div>

View File

@ -38,12 +38,16 @@
{% endif %}
{% for booking in desk_info.bookings %}
<div class="booking{% if booking.color %} booking-color-{{ booking.color.index }}{% endif %}"
<div class="booking{% if booking.color %} booking-color-{{ booking.color.index }}{% endif %}{% if booking.lease %} lease{% endif %}"
style="height: {{ booking.css_height }}%; min-height: {{ booking.css_height }}%; top: {{ booking.css_top }}%;"
><span class="start-time">{{booking.event.start_datetime|date:"TIME_FORMAT"}}</span>
<a {% if booking.get_backoffice_url %}href="{{booking.get_backoffice_url}}"{% endif %}>{{ booking.get_user_block }}</a>
<a rel="popup" class="cancel" href="{% url 'chrono-manager-booking-cancel' pk=booking.event.agenda_id booking_pk=booking.pk %}?next={{ request.path }}">{% trans "Cancel" %}</a>
{% if booking.color %}<span class="booking-color-label booking-bg-color-{{ booking.color.index }}">{{ booking.color }}</span>{% endif %}
{% if booking.lease %}
{% trans "Currently being booked..." %}
{% else %}
<a {% if booking.get_backoffice_url %}href="{{booking.get_backoffice_url}}"{% endif %}>{{ booking.get_user_block }}</a>
<a rel="popup" class="cancel" href="{% url 'chrono-manager-booking-cancel' pk=booking.event.agenda_id booking_pk=booking.pk %}?next={{ request.path }}">{% trans "Cancel" %}</a>
{% if booking.color %}<span class="booking-color-label booking-bg-color-{{ booking.color.index }}">{{ booking.color }}</span>{% endif %}
{% endif %}
</div>
{% endfor %}
</td>

View File

@ -31,12 +31,16 @@
{% endfor %}
{% for slot in day.infos.booked_slots %}
<div class="booking{% if slot.booking.color %} booking-color-{{ slot.booking.color.index }}{% endif %}" style="left:{{ slot.css_left|stringformat:".1f" }}%;height:{{ slot.css_height|stringformat:".1f" }}%;min-height:{{ slot.css_height|stringformat:".1f" }}%;top:{{ slot.css_top|stringformat:".1f" }}%;width:{{ slot.css_width|stringformat:".1f" }}%;">
<div class="booking{% if slot.booking.color %} booking-color-{{ slot.booking.color.index }}{% endif %}{% if slot.booking.lease %} lease{% endif %}" style="left:{{ slot.css_left|stringformat:".1f" }}%;height:{{ slot.css_height|stringformat:".1f" }}%;min-height:{{ slot.css_height|stringformat:".1f" }}%;top:{{ slot.css_top|stringformat:".1f" }}%;width:{{ slot.css_width|stringformat:".1f" }}%;">
<span class="start-time">{{slot.booking.event.start_datetime|date:"TIME_FORMAT"}}</span>
<a {% if slot.booking.get_backoffice_url %}href="{{slot.booking.get_backoffice_url}}"{% endif %}>{{ slot.booking.get_user_block }}</a>
<a rel="popup" class="cancel" href="{% url 'chrono-manager-booking-cancel' pk=slot.booking.event.agenda_id booking_pk=slot.booking.id %}?next={{ request.path }}">{% trans "Cancel" %}</a>
{% if not single_desk %}<span class="desk">{{ slot.desk }}</span>{% endif %}
{% if slot.booking.color %}<span class="booking-color-label booking-bg-color-{{ slot.booking.color.index }}">{{ slot.booking.color }}</span>{% endif %}
{% if slot.booking.lease %}
{% trans "Currently being booked..." %}
{% else %}
<a {% if slot.booking.get_backoffice_url %}href="{{slot.booking.get_backoffice_url}}"{% endif %}>{{ slot.booking.get_user_block }}</a>
<a rel="popup" class="cancel" href="{% url 'chrono-manager-booking-cancel' pk=slot.booking.event.agenda_id booking_pk=slot.booking.id %}?next={{ request.path }}">{% trans "Cancel" %}</a>
{% if not single_desk %}<span class="desk">{{ slot.desk }}</span>{% endif %}
{% if slot.booking.color %}<span class="booking-color-label booking-bg-color-{{ slot.booking.color.index }}">{{ slot.booking.color }}</span>{% endif %}
{% endif %}
</div>
{% endfor %}
{% endif %}

View File

@ -316,7 +316,7 @@ class ResourceDayView(DateMixin, DayArchiveView):
queryset = (
self.resource.event_set.all()
.select_related('meeting_type', 'agenda')
.prefetch_related('booking_set')
.prefetch_related('booking_set', 'booking_set__lease')
)
return queryset
@ -432,7 +432,7 @@ class ResourceWeekMonthMixin:
queryset = (
self.resource.event_set.all()
.select_related('meeting_type', 'agenda')
.prefetch_related('booking_set')
.prefetch_related('booking_set', 'booking_set__lease')
)
return queryset
@ -1359,7 +1359,7 @@ class AgendaDateView(DateMixin, ViewableAgendaMixin):
queryset = (
Event.objects.filter(agenda__virtual_agendas=self.agenda)
.select_related('meeting_type', 'agenda')
.prefetch_related('booking_set')
.prefetch_related('booking_set', 'booking_set__lease')
)
return queryset
@ -2770,12 +2770,13 @@ class EventDetailView(ViewableAgendaMixin, DetailView):
context = super().get_context_data(**kwargs)
context['user_can_manage'] = self.agenda.can_be_managed(self.request.user)
event = self.object
bookings = event.booking_set.select_related('lease')
context['booked'] = (
event.booking_set.filter(cancellation_datetime__isnull=True, in_waiting_list=False)
bookings.filter(cancellation_datetime__isnull=True, in_waiting_list=False)
.prefetch_related('user_checks')
.order_by('creation_datetime')
)
context['waiting'] = event.booking_set.filter(
context['waiting'] = bookings.filter(
cancellation_datetime__isnull=True, in_waiting_list=True
).order_by('creation_datetime')
event.present_count = len([b for b in context['booked'] if b.user_check and b.user_check.presence])

View File

@ -1046,7 +1046,7 @@ def test_agenda_day_view(app, admin_user, manager_user, api_user):
resp = app.get(
'/manage/agendas/%s/day/%d/%d/%d/' % (agenda.id, date.year, date.month, date.day), status=200
)
assert len(ctx.captured_queries) == 14
assert len(ctx.captured_queries) == 15
# day is displaying rows from 10am to 6pm,
# opening hours, 10am to 1pm gives top: 300%
# calendar exception, 1pm to 3pm gives heigh: 200%
@ -2635,7 +2635,7 @@ def test_virtual_agenda_day_view(app, admin_user, manager_user):
resp = app.get(
'/manage/agendas/%s/day/%d/%d/%d/' % (agenda.id, date.year, date.month, date.day), status=200
)
assert len(ctx.captured_queries) == 16
assert len(ctx.captured_queries) == 17
# day is displaying rows from 10am to 6pm,
# opening hours, 10am to 1pm gives top: 300%
# rest of the day, 1pm to 6(+1)pm gives 600%
@ -4030,3 +4030,40 @@ def test_agenda_today_button(app, admin_user):
resp = app.get('/manage/agendas/%s/week/%s/%s/%s/' % (agenda.pk, today.year, today.month, today.day))
assert 'Today' not in resp.pyquery('a.active').text()
def test_meeting_agenda_lease_display(app, admin_user, manager_user, api_user):
agenda = Agenda.objects.create(label='New Example', kind='meetings')
desk = Desk.objects.create(agenda=agenda, label='New Desk')
meetingtype = MeetingType.objects.create(agenda=agenda, label='Bar', duration=30)
today = datetime.date.today()
TimePeriod.objects.create(
desk=desk, weekday=today.weekday(), start_time=datetime.time(10, 0), end_time=datetime.time(18, 30)
)
# Create a leased booking
app.reset()
app.authorization = ('Basic', ('john.doe', 'password'))
resp = app.get('/api/agenda/%s/meetings/%s/datetimes/' % (agenda.slug, meetingtype.slug))
booking_url = resp.json['data'][0]['api']['fillslot_url']
app.post(booking_url, params={'lock_code': 'ABCD'})
date = Booking.objects.all()[0].event.start_datetime
app.reset()
login(app)
# Display agenda on day of the leased booking
resp = app.get('/manage/agendas/%s/day/%d/%d/%d/' % (agenda.id, date.year, date.month, date.day))
assert len(resp.pyquery('.booking')) == 1
assert len(resp.pyquery('.booking.lease')) == 1
assert 'Currently being booked...' in resp.pyquery('.booking.lease').text()
resp = app.get('/manage/agendas/%s/week/%d/%d/%d/' % (agenda.id, date.year, date.month, date.day))
assert len(resp.pyquery('.booking')) == 1
assert len(resp.pyquery('.booking.lease')) == 1
assert 'Currently being booked...' in resp.pyquery('.booking.lease').text()
resp = app.get('/manage/agendas/%s/month/%d/%d/%d/' % (agenda.id, date.year, date.month, date.day))
assert len(resp.pyquery('.booking')) == 1
assert len(resp.pyquery('.booking.lease')) == 1
assert 'Currently being booked...' in resp.pyquery('.booking.lease').text()

View File

@ -11,7 +11,7 @@ from django.test import override_settings
from django.test.utils import CaptureQueriesContext
from webtest import Upload
from chrono.agendas.models import Agenda, Booking, Desk, Event, EventsType, Subscription
from chrono.agendas.models import Agenda, Booking, Desk, Event, EventsType, Lease, Subscription
from chrono.utils.lingo import CheckType
from chrono.utils.timezone import localtime, make_aware, now
from tests.utils import login
@ -3381,3 +3381,25 @@ def test_duplicate_event_creates_recurrences(app, admin_user):
event_recurrence = duplicate.recurrences.first()
app.get(f'/manage/agendas/{agenda.pk}/events/{event_recurrence.pk}/duplicate', status=404)
@pytest.mark.freeze_time('2022-05-24')
def test_event_detail_lease_display(app, admin_user):
agenda = Agenda.objects.create(label='Events', kind='events')
event = Event.objects.create(
label='xyz',
start_datetime=now() + datetime.timedelta(days=1),
places=10,
waiting_list_places=2,
agenda=agenda,
)
booking1 = Booking.objects.create(event=event, user_last_name="User's 1")
booking2 = Booking.objects.create(event=event, user_last_name='User 2', in_waiting_list=True)
Lease.objects.create(booking=booking1, lock_code='ABCD')
Lease.objects.create(booking=booking2, lock_code='ABCD')
login(app)
resp = app.get('/manage/agendas/%d/events/%d/' % (agenda.pk, event.pk))
assert 'Bookings (1/10)' in resp.text
assert 'Waiting List (1/2): 1 remaining place' in resp.text
assert resp.text.count('Currently being booked...') == 2

View File

@ -126,7 +126,7 @@ def test_resource_day_view(app, admin_user):
resp = app.get(
'/manage/resource/%s/day/%d/%d/%d/' % (resource.pk, today.year, today.month, today.day)
)
assert len(ctx.captured_queries) == 7
assert len(ctx.captured_queries) == 8
assert resp.text.count('div class="booking') == 2
assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == 'booked'
assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "foo - bar's"
@ -279,7 +279,7 @@ def test_resource_week_view(app, admin_user):
resp = app.get(
'/manage/resource/%s/week/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day)
)
assert len(ctx.captured_queries) == 8
assert len(ctx.captured_queries) == 9
assert resp.text.count('<div class="booking" style="height:33.0%;') == 2 # booking cells
assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == 'booked'
assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "foo - bar's"
@ -625,7 +625,7 @@ def test_resource_month_view(app, admin_user):
resp = app.get(
'/manage/resource/%s/month/%s/%s/%s/' % (resource.pk, today.year, today.month, today.day)
)
assert len(ctx.captured_queries) == 8
assert len(ctx.captured_queries) == 9
assert resp.text.count('<div class="booking" style="height:33.0%;') == 2 # booking cells
assert resp.pyquery.find('div.booking a').not_('.cancel')[0].text.strip() == 'booked'
assert resp.pyquery.find('div.booking a').not_('.cancel')[1].text.strip() == "foo - bar's"