from events.models import RSVP, Activity, Question, Response def summary_email(rsvp:RSVP) -> str: summary = f"Email: You will receive updates at `{rsvp.responder_email}`" if rsvp.send_email_updates == False: summary = f"Email: You do not want any updates." return summary def summary_guests(rsvp:RSVP) -> str: summary = f"Guests: let us know who will come!" if rsvp.is_page_finished(RSVP.Page.GUESTS): guests = rsvp.guest_count if guests == 0: summary = f"Guests: Don't forget to add yourself!" if guests == 1: summary = f"Guests: Just you." if guests > 1: summary = f"Guests: You are coming with {guests} people." return summary def summary_activities(rsvp:RSVP) -> str: summary = f"Activities" chosen_activities_count = rsvp.activities.count() available_activities = Activity.objects.filter(event=rsvp.event) total_activities_count = len(available_activities) activities_with_space_count = sum( 1 for a in available_activities if a.remaining_capacity() >= rsvp.guest_count ) if rsvp.is_page_finished(RSVP.Page.ACTIVITIES) and chosen_activities_count > 0: if chosen_activities_count == 1: summary = f"Activities: You have selected one activity!" if chosen_activities_count > 1: summary = f"Activities: You have selected {chosen_activities_count} activities!" else: summary = f"Activities: You can still choose from {activities_with_space_count} / {total_activities_count} activities!" return summary def summary_questions(rsvp:RSVP) -> str: selected_activities = rsvp.activities.all() if not selected_activities.exists(): return "Questions: No activities selected — no questions to answer." questions = Question.objects.filter(activity__in=selected_activities) total = questions.count() if total == 0: return "Questions: No questions for your selected activities." def is_answered(q: Question) -> bool: if q.scope == "rsvp": resp = Response.objects.filter(rsvp=rsvp, question=q).first() if not resp: return False if q.kind in ("text", "integer", "boolean"): return bool(resp.value_text and resp.value_text.strip()) return resp.choices.exists() # guest-scoped guests = rsvp.guests.all() if not guests: return False for guest in guests: resp = Response.objects.filter(guest=guest, question=q).first() if not resp: return False if q.kind in ("text", "integer", "boolean"): if not (resp.value_text and resp.value_text.strip()): return False else: if resp.choices.count() == 0: return False return True answered = sum(1 for q in questions if is_answered(q)) unanswered = total - answered required_total = questions.filter(required=True).count() required_unanswered = sum(1 for q in questions.filter(required=True) if not is_answered(q)) if rsvp.is_page_finished(RSVP.Page.QUESTIONS): if unanswered == 0: summary = f"Questions: All {total} answered." else: summary = f"Questions: {answered} answered, {unanswered} remaining." else: summary = f"Questions: {answered} answered, {unanswered} remaining." if required_unanswered > 0: summary += f" ({required_unanswered} required unanswered)" return summary def summary_notes(rsvp:RSVP) -> str: summary = f"Notes: anything you want to share?" if len(rsvp.notes) > 1: summary = f"Notes: you have left a note." return summary