import os import django os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings') django.setup() from django.shortcuts import render, redirect, get_object_or_404 from django.urls import reverse from django.contrib import messages from django.utils import timezone from core.models import Tenant, CampaignSettings, Volunteer, Voter, InteractionType, Interaction, ScheduledCall from core.forms import DoorVisitLogForm import zoneinfo def log_door_visit(request): """ Mark all targeted voters at a specific address as visited, update their flags, and create interaction records. Can also render a standalone page for logging a visit. """ selected_tenant_id = request.session.get("tenant_id") if not selected_tenant_id: return redirect("index") tenant = get_object_or_404(Tenant, id=selected_tenant_id) campaign_settings, _ = CampaignSettings.objects.get_or_create(tenant=tenant) # Capture query string for redirecting back with filters next_qs = request.POST.get("next_query_string", request.GET.get("next_query_string", "")) redirect_url = reverse("door_visits") if next_qs: redirect_url += f"?{next_qs}" # Get address components from POST or GET address_street = request.POST.get("address_street", request.GET.get("address_street")) city = request.POST.get("city", request.GET.get("city")) state = request.POST.get("state", request.GET.get("state")) zip_code = request.POST.get("zip_code", request.GET.get("zip_code")) if not address_street: messages.warning(request, "No address provided.") return redirect(redirect_url) # Find targeted voters at this exact address voters = Voter.objects.filter( tenant=tenant, address_street=address_street, city=city, state=state, zip_code=zip_code, is_targeted=True ) if not voters.exists() and request.method == "POST": messages.warning(request, f"No targeted voters found at {address_street}.") return redirect(redirect_url) voter_choices = [(v.id, f"{v.first_name} {v.last_name}") for v in voters] # Get the volunteer linked to the current user volunteer = Volunteer.objects.filter(user=request.user, tenant=tenant).first() if request.method == "POST": form = DoorVisitLogForm(request.POST, voter_choices=voter_choices) if form.is_valid(): outcome = form.cleaned_data["outcome"] notes = form.cleaned_data["notes"] wants_yard_sign = form.cleaned_data["wants_yard_sign"] candidate_support = form.cleaned_data["candidate_support"] follow_up = form.cleaned_data["follow_up"] follow_up_voter_id = form.cleaned_data.get("follow_up_voter") call_notes = form.cleaned_data["call_notes"] # Determine date/time in campaign timezone campaign_tz_name = campaign_settings.timezone or "America/Chicago" try: tz = zoneinfo.ZoneInfo(campaign_tz_name) except: tz = zoneinfo.ZoneInfo("America/Chicago") interaction_date = timezone.now().astimezone(tz) # Get or create InteractionType interaction_type, _ = InteractionType.objects.get_or_create(tenant=tenant, name="Door Visit") # Get default caller for follow-ups default_caller = None if follow_up: default_caller = Volunteer.objects.filter(tenant=tenant, is_default_caller=True).first() for voter in voters: # 1) Update voter flags voter.door_visit = True # 2) If "Wants a Yard Sign" checkbox is selected if wants_yard_sign: voter.yard_sign = "wants" # 3) Update support status if Supporting or Not Supporting if candidate_support in ["supporting", "not_supporting"]: voter.candidate_support = candidate_support voter.save() # 4) Create interaction Interaction.objects.create( voter=voter, volunteer=volunteer, type=interaction_type, date=interaction_date, description=outcome, notes=notes ) # 5) Create ScheduledCall if follow_up is checked and this is the selected voter if follow_up and follow_up_voter_id and str(voter.id) == follow_up_voter_id: ScheduledCall.objects.create( tenant=tenant, voter=voter, volunteer=default_caller, comments=call_notes, status="pending" ) if follow_up: messages.success(request, f"Door visit logged and follow-up call scheduled for {address_street}.") else: messages.success(request, f"Door visit logged for {address_street}.") return redirect(redirect_url) else: if request.headers.get('x-requested-with') == 'XMLHttpRequest': # If it's the modal, we might want to handle it differently, # but currently it's a standard POST from modal. pass messages.error(request, "There was an error in the visit log form.") else: # GET request: render standalone page form = DoorVisitLogForm(voter_choices=voter_choices) context = { 'selected_tenant': tenant, 'visit_form': form, 'address_street': address_street, 'city': city, 'state': state, 'zip_code': zip_code, 'voters': voters, 'next_query_string': next_qs, } return render(request, 'core/log_door_visit.html', context) return redirect(redirect_url)