import os import django os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings') django.setup() import re from core import views def patch_log_door_visit(): with open('core/views.py', 'r') as f: content = f.read() new_view = """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: messages.error(request, "There was an error in the visit log form.") return redirect(redirect_url) 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) """ # Replace the old function. We use regex to find the start and then match indentation for the end. pattern = r'def log_door_visit\(request\):.*?return redirect\(redirect_url\)' content = re.sub(pattern, new_view, content, flags=re.DOTALL) with open('core/views.py', 'w') as f: f.write(content) if __name__ == "__main__": patch_log_door_visit()