fix(calendar): include guests in attendee counts everywhere
Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions

Event attendee counts were inconsistent - event detail page showed total
(members + guests = 42) but event list and homepage showed only members (39).
Now all views use total_attendee_count including guests (osoby towarzyszące).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maciej Pienczyn 2026-04-08 15:29:05 +02:00
parent a85310ddb7
commit c6326d9760
6 changed files with 17 additions and 11 deletions

View File

@ -347,7 +347,7 @@ def rsvp(event_id):
'success': True, 'success': True,
'action': 'removed', 'action': 'removed',
'message': msg_removed, 'message': msg_removed,
'attendee_count': event.attendee_count 'attendee_count': event.total_attendee_count
}) })
else: else:
# Skip max_attendees check for external events # Skip max_attendees check for external events
@ -370,7 +370,7 @@ def rsvp(event_id):
'success': True, 'success': True,
'action': 'added', 'action': 'added',
'message': msg_added, 'message': msg_added,
'attendee_count': event.attendee_count 'attendee_count': event.total_attendee_count
}) })
finally: finally:
db.close() db.close()

View File

@ -35,6 +35,7 @@ from database import (
CompanyPKD, CompanyPKD,
NordaEvent, NordaEvent,
EventAttendee, EventAttendee,
EventGuest,
AIChatConversation, AIChatConversation,
AIChatMessage, AIChatMessage,
UserSession, UserSession,
@ -322,7 +323,7 @@ def api_upcoming_events():
'day': days[event.event_date.weekday()], 'day': days[event.event_date.weekday()],
'time': event.time_start.strftime('%H:%M') if event.time_start else None, 'time': event.time_start.strftime('%H:%M') if event.time_start else None,
'location': (event.location[:30] + '...' if event.location and len(event.location) > 30 else event.location) if event.location else None, 'location': (event.location[:30] + '...' if event.location and len(event.location) > 30 else event.location) if event.location else None,
'attendee_count': event.attendee_count, 'attendee_count': event.total_attendee_count,
'is_external': event.is_external, 'is_external': event.is_external,
'external_source': event.external_source, 'external_source': event.external_source,
'access_level': event.access_level, 'access_level': event.access_level,
@ -1129,13 +1130,18 @@ def dashboard():
).all() ).all()
user_event_ids = {r[0] for r in rsvps} user_event_ids = {r[0] for r in rsvps}
# Count confirmed attendees per event # Count confirmed attendees + guests per event
from sqlalchemy import func from sqlalchemy import func
counts = db.query(EventAttendee.event_id, func.count(EventAttendee.id)).filter( counts = db.query(EventAttendee.event_id, func.count(EventAttendee.id)).filter(
EventAttendee.event_id.in_(event_ids), EventAttendee.event_id.in_(event_ids),
EventAttendee.status == 'confirmed' EventAttendee.status == 'confirmed'
).group_by(EventAttendee.event_id).all() ).group_by(EventAttendee.event_id).all()
event_attendee_counts = {eid: cnt for eid, cnt in counts} event_attendee_counts = {eid: cnt for eid, cnt in counts}
guest_counts = db.query(EventGuest.event_id, func.count(EventGuest.id)).filter(
EventGuest.event_id.in_(event_ids)
).group_by(EventGuest.event_id).all()
for eid, cnt in guest_counts:
event_attendee_counts[eid] = event_attendee_counts.get(eid, 0) + cnt
# Widget 2: Recent announcements (3 latest published, pinned first, not expired) # Widget 2: Recent announcements (3 latest published, pinned first, not expired)
recent_announcements = db.query(Announcement).filter( recent_announcements = db.query(Announcement).filter(

View File

@ -143,7 +143,7 @@
<td>{{ event.event_date.strftime('%d.%m.%Y') }}</td> <td>{{ event.event_date.strftime('%d.%m.%Y') }}</td>
<td>{{ event.event_type }}</td> <td>{{ event.event_type }}</td>
<td>{{ event.location or '-' }}</td> <td>{{ event.location or '-' }}</td>
<td>{{ event.attendee_count }}</td> <td>{{ event.total_attendee_count }}</td>
<td> <td>
{% if event.is_past %} {% if event.is_past %}
<span class="badge badge-past">Zakonczone</span> <span class="badge badge-past">Zakonczone</span>

View File

@ -714,7 +714,7 @@
{% endif %} {% endif %}
{% else %} {% else %}
<div class="rsvp-section" style="background: var(--border);"> <div class="rsvp-section" style="background: var(--border);">
<p class="text-muted" style="margin: 0;">To wydarzenie już się odbyło.{% if event.can_user_see_attendees(current_user) %} {{ event.attendee_count }} osób brało udział.{% endif %}</p> <p class="text-muted" style="margin: 0;">To wydarzenie już się odbyło.{% if event.can_user_see_attendees(current_user) %} {{ event.total_attendee_count }} osób brało udział.{% endif %}</p>
</div> </div>
{% endif %} {% endif %}

View File

@ -760,7 +760,7 @@
</div> </div>
<div class="event-actions"> <div class="event-actions">
{% if event.is_external %} {% if event.is_external %}
<span class="attendee-count">{{ event.attendee_count }} zainteresowanych</span> <span class="attendee-count">{{ event.total_attendee_count }} zainteresowanych</span>
{% if event.can_user_attend(current_user) %} {% if event.can_user_attend(current_user) %}
{% set is_attending = event.attendees|selectattr('user_id','equalto',current_user.id)|list %} {% set is_attending = event.attendees|selectattr('user_id','equalto',current_user.id)|list %}
<button class="btn btn-sm rsvp-list-btn {{ 'rsvp-attending' if is_attending else 'rsvp-not-attending' }}" data-event-id="{{ event.id }}" data-attending="{{ 'true' if is_attending else 'false' }}" data-external="true" onclick="toggleListRSVP(this)" {{ 'onmouseenter=this.textContent="Nie interesuje" onmouseleave=this.textContent="Zainteresowany "'|safe if is_attending }}> <button class="btn btn-sm rsvp-list-btn {{ 'rsvp-attending' if is_attending else 'rsvp-not-attending' }}" data-event-id="{{ event.id }}" data-attending="{{ 'true' if is_attending else 'false' }}" data-external="true" onclick="toggleListRSVP(this)" {{ 'onmouseenter=this.textContent="Nie interesuje" onmouseleave=this.textContent="Zainteresowany "'|safe if is_attending }}>
@ -768,7 +768,7 @@
</button> </button>
{% endif %} {% endif %}
{% else %} {% else %}
<span class="attendee-count">{{ event.attendee_count }} uczestników</span> <span class="attendee-count">{{ event.total_attendee_count }} uczestników</span>
{% if event.can_user_attend(current_user) %} {% if event.can_user_attend(current_user) %}
{% set is_attending = event.attendees|selectattr('user_id','equalto',current_user.id)|list %} {% set is_attending = event.attendees|selectattr('user_id','equalto',current_user.id)|list %}
<button class="btn btn-sm rsvp-list-btn {{ 'rsvp-attending' if is_attending else 'rsvp-not-attending' }}" data-event-id="{{ event.id }}" data-attending="{{ 'true' if is_attending else 'false' }}" data-external="false" onclick="toggleListRSVP(this)" {{ 'onmouseenter=this.textContent="Wypisz się" onmouseleave=this.textContent="Zapisano "'|safe if is_attending }}> <button class="btn btn-sm rsvp-list-btn {{ 'rsvp-attending' if is_attending else 'rsvp-not-attending' }}" data-event-id="{{ event.id }}" data-attending="{{ 'true' if is_attending else 'false' }}" data-external="false" onclick="toggleListRSVP(this)" {{ 'onmouseenter=this.textContent="Wypisz się" onmouseleave=this.textContent="Zapisano "'|safe if is_attending }}>
@ -810,7 +810,7 @@
</div> </div>
</div> </div>
<div class="event-actions"> <div class="event-actions">
<span class="attendee-count">{{ event.attendee_count }} uczestników</span> <span class="attendee-count">{{ event.total_attendee_count }} uczestników</span>
</div> </div>
</div> </div>
{% endfor %} {% endfor %}

View File

@ -1136,7 +1136,7 @@
</div> </div>
<div class="event-banner-bottom"> <div class="event-banner-bottom">
<div class="event-banner-attendees"> <div class="event-banner-attendees">
👥 Zapisanych: {{ ev.attendee_count }} {% if ev.attendee_count == 1 %}osoba{% elif ev.attendee_count in [2,3,4] %}osoby{% else %}osób{% endif %} 👥 Zapisanych: {{ ev.total_attendee_count }} {% if ev.total_attendee_count == 1 %}osoba{% elif ev.total_attendee_count in [2,3,4] %}osoby{% else %}osób{% endif %}
</div> </div>
<div class="event-banner-action"> <div class="event-banner-action">
{% if ue.user_registered %} {% if ue.user_registered %}
@ -1505,7 +1505,7 @@
let timePart = ev.time ? '<span>🕕 ' + ev.time + '</span>' : ''; let timePart = ev.time ? '<span>🕕 ' + ev.time + '</span>' : '';
let locPart = ev.location ? '<span>📍 ' + ev.location + '</span>' : ''; let locPart = ev.location ? '<span>📍 ' + ev.location + '</span>' : '';
let cnt = ev.attendee_count; let cnt = ev.total_attendee_count;
let cntWord = cnt === 1 ? 'osoba' : (cnt >= 2 && cnt <= 4 ? 'osoby' : 'osób'); let cntWord = cnt === 1 ? 'osoba' : (cnt >= 2 && cnt <= 4 ? 'osoby' : 'osób');
let actionHtml = ''; let actionHtml = '';