From 442aec63b65984a34d277f2cf309d54fe9dff2a1 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Sun, 1 Feb 2026 06:28:41 +0000 Subject: [PATCH] 3.0 --- config/__pycache__/settings.cpython-311.pyc | Bin 5917 -> 5953 bytes config/settings.py | 3 +- core/__pycache__/middleware.cpython-311.pyc | Bin 1861 -> 3307 bytes core/__pycache__/views.cpython-311.pyc | Bin 80868 -> 82781 bytes core/middleware.py | 37 +++++++- core/templates/core/door_visit_history.html | 86 +++++++++++++++--- core/templates/core/door_visits.html | 1 + core/views.py | 96 +++++++++++++------- core_view_fix.tmp | 14 +++ 9 files changed, 192 insertions(+), 45 deletions(-) create mode 100644 core_view_fix.tmp diff --git a/config/__pycache__/settings.cpython-311.pyc b/config/__pycache__/settings.cpython-311.pyc index 45dee05ed9fe208f5350823c0d467c66804e7997..f390f90fb445142863fbaa4b5395c10f8fd9e57d 100644 GIT binary patch delta 98 zcmbQMcTkUaIWI340}#kOugl!Nk#`v}sd~AYDJeOr<%vLMNM>$o vReoOTQHm_9JThz70?Qkxq@<}v{QBcC7! delta 64 zcmX@8H&>5$IWI340}$8?*Jk!@FA9rk>wjzpJRb4lRI8YAj4$CD9u~#{Aoax!6 zQT)rzuS)fI_y#OuY%y`s9J-%?Cd)mIFMT~_p>ZtgtX9NdQv zzoM80q!{+zJhyej zWvz+8w{YM3AuyKi$3!%NVIQCb(fbIHjrV}FM%ip86&P^AS@1s~+?|K7hx(U0`>=B~ zQ%58V6eS>FFv#wv(|&L=<@(EA_B*O9Ysy*?DVGWbRaebIfuw`t1V~1u<3EE30sPYV zef}}@Yhi<`!7?`ZvWu-m>VDTn8SY`nqmC1R4Z237`4BLfE(3rv3F}EWNO$b_HTo;+ zR1~Jhl#e59PqdTyP8S1tRrRe zhdrsCn!Yy~2=t3t06P(v{ZGor;rFoNk#EH4rE<Y~|@(9hX17hPz*z@>JE*I90jq_30B`LD<#uFWN8k6qpBE7RrAgJs$n`@v1F?6 z7fr?C$l+1-yH$tFW9@CCg=MAdM_$zjkceZT`Ur`{n(KP8qIfeqeWlKsD;S+aXOMmO z4uxNEq@G?-aHXQA6$%$H!T1RSJ~4gCE!Jg0^86?79wx>Q660S+nu%#UF})RPMG|!v z1VTxdVxq~T+_asWJIpN{?S`0Xr6%pv)opg0Z6C$6cKosnU^ICG zEitjpxHPu4+ih0_e7_6W(1=UX(Xk_Oz!o!~PuL?@zrNWVnYBk|o8p`;&NaMNZ@U!i zu(C~Y)D}k@-G+nx%qMJqxXEX1KGWbcKML_fA$=gEcVB7>k}XILPBMn@I(Nsfao`Cj zTpOgHq#(ic*kTYo4JH>~p_h<^Dd-}BlPh7045vuBkCQuLA{Ce;pK8sU#VVNHC3%s4v|t7pZQ8vR=C`~`4@B|jl%!{ delta 450 zcmaDYd6bWDIWI340}x~g*JgIHOyraBcLDOIGo&!2Fy=7iGDa~ng4j$sOu5Wa%wRTi z4ofa;6e}YG6N5WL3QG$^3hOc^28Pu@3;|JWDQv+En(Qw@+=*M1CtqMQpKQkHDW%DH zizhv`B)%xMxFA2TI8~GB7E5tzPFfMypUNJIqPX5fS&B!xZp2e9_ zc5*U{1tZ_&IV=twAh&9A6md^}!r~?@22#%fBorXPp@?U)EvvpVCrJDdkoeKSaD!j0 zr{)U3&IblDPMaITQdfjkI$S<*Ozvmh#;7^jjZIB~7pSmE2}rDDDB=ULc|Zg^j9{H? z%dM;;#VYZE0h54e0IBuUWS`u@ZEXnAs0PvvH|!UOO>TZlX-=wLkrq&b5r~U(fy4)9 dMn=ZTIy`3PA6VoVffisAA3svM zODUx#VQ3W~DNcc~g+CCL0{z<5v}JjeQk$A$ZV3&KmKGi@2FjxZTHZP5%DS@SQ2Kp; zeeq9oXXehFZO)uols|rKIDNe_>)y=FbO}E853csU_s*fL!pN;UNs3CcBr~7nXHLd2 zt@G*pI;YOBck2BHr-AbHKBLnJWqO~?>GYi8%%E?x(+uARU#36H zndP@QE!2+Dm+jAS=1|(?yC~P6=gjk4omRiiX`{>(U%tPP{p7SeO7ugE{eIfc?` zzG8ogvxL&=zEXdgvkcN1ve|d&jpkzibmw$`gR{Zk=xp>iIh*`5oHM96(og!CEymh3eYK6170E50A49i z1-weG1>7pv0lH)d;5NA)&@E5b&jj?! zEr6Z!EWlmz1%N*JLO{Pf8!#Zx0qm0J0(Q&u0C&st0lBQdRB|kM8^z;bN_w}O2R$y? z9r8HzN@@`%LSDZ|F%YI9${t_H9lJ+2lrd!vyv4yBrTdv;3V8zVKJ|9YzH201j+_MAP=2=*~3^Ox#ctWl&?&{zkEZ8XC%bv9; z6N}3cYzReIF|~`!9`0)2&ztd4AL!c4uf$RuCyp#7g?o1Qc!D8*m2l@2wr#~C7s56K zH^NSYO97Oe4!6JC?cEV@1wEmVH?Sk9Fc;s5<(FZ3N=H{9?+QqFASe#k9~ zW#tYTBD1ho3qWuFmaZPVn|tg)i{0-IxOYHH^XwceJ5sqBD_RjQKp+WOAf==PdpbHi z!JuLYxcwfU0eKER4`L;3m(K$T>H+L_JKqQ2iY4grc{)NaAX{uLFd46g%=N-su!Z%C z_n$3_y;iU=m9>Z|_L?m0oFk12+s)^Swf18BLVPlWc#mfzUw~;Kpu4+^hxj6_yja{| zub$b8$)!}f#~bv9JThO7Sr;L+A*@7Lg>W&#YVo@L4{V<}Rnf%0D*jgCSltWRZ=+q1 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 delta 16648 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

PlL zF<*mHSFbNZ<2#dS+KHCfLk&v(Vr)b3;No9vkPn=P^2~fa}U~+(vEF;e8om6O{|4;s$5qFt5 zEp5tHt;cL}-}tDzMz+=D%T+a{l6=?PK8xSfml3rrHQlaUwW7}&wHh9?k38ZI%pUv^ z<*82xofuS0J7-cR)WIJb#Up%Q{5k2P=ouccz^H#9lR8rD#gZInHhJ01uyV6EnknOvt)r){J4#a0uqOUQrps^J%IZ}| z)T-w0cSJLycIX%1hQn3K`O0;&rqE`%uQ*GUv0YP@s{T>+UAxS?%qi{jdP$n?mUc7u zol45c_v9OGc9M;d2~8rs7=(|i9q+Bww2XNYV{1eSmOGlQ|9BA56D{1~LE*t63X%5Uj zSjUsh<{a0wK1b9Xb*Sb0&3(C%1pU-4``FyWWX(rm(fpww7FNb=)0Nd}kNv06h$7E6 zgQ{xTI1z8<0h!{{Hc^q_z!SkHhr{%1D&8@pYjzao&=0`8yVDN-WK5>H=y!Cnc{7yC zO?22qKf%Y6P}?QL$_jl6uV;^Gr1NJ)esKCT~ULSV?2@^U>`yX0Y~CSq~X{fHO1D?QcC-W zQ3cBgEd#x>bTmhtUH$OuFsg8@n#|V&Rmu-TN3|n9`o4Ine)RrCsqtinm;^g{@F~EHUF%`R8cjUQF6Mp;jF2~x>EU= z@rIn!j?!Vrm>ZP0V~ul^Z<-q>#4Ih!q`Ei8H6GgZgH5N$jXynp`q}c_3C^=7fXoN*Ru1N@Jl(Q%xMdahIP7Q`96M{sG5hrFMZ>e#B=Qcf9dgV(J%2^w zd2sBUAxFz+|6W)+ST^xDWz$c^e$t}s=s#<|!^}Qx=tJR*GooGF2@q)B)-N4f5*A zV`5*Aj5 + +

+ +
+
+
+
Filter by Date Range
+
+
+ + +
+
+ + +
+
+ +
+ {% if start_date or end_date %} + + {% endif %} +
+
+
+
+ + +
+
+
+
Visits per Volunteer
+
+ {% for v_name, count in volunteer_counts %} +
+ {{ v_name }} + {{ count }} +
+ {% empty %} +

No volunteer data available for this selection.

+ {% endfor %} +
+
+
+
+
+
@@ -33,8 +84,9 @@ Household Address Voters Visited Last Visit + Volunteer Outcome - Interactions + Comments @@ -66,25 +118,37 @@
{{ household.last_visit_date|date:"M d, Y" }}
{{ household.last_visit_date|date:"H:i" }}
+ + {% if household.last_volunteer %} +
+
+ {{ household.last_volunteer.first_name|first }}{{ household.last_volunteer.last_name|first }} +
+ {{ household.last_volunteer }} +
+ {% else %} + N/A + {% endif %} + {{ household.last_outcome }} - - {{ household.interaction_count }} Visit{{ household.interaction_count|pluralize }} - +
+ {{ household.notes|default:"-" }} +
{% empty %} - +
-

No door visits logged yet.

-

Visit the Planned Visits page to start logging visits.

+

No door visits found for this selection.

+

Try clearing your filters or visit the Planned Visits page to log more visits.

{% endfor %} @@ -98,12 +162,12 @@
    {% if history.has_previous %}
  • - +
  • - +
  • @@ -113,12 +177,12 @@ {% if history.has_next %}
  • - +
  • - +
  • diff --git a/core/templates/core/door_visits.html b/core/templates/core/door_visits.html index 91fbd48..72c9cbc 100644 --- a/core/templates/core/door_visits.html +++ b/core/templates/core/door_visits.html @@ -196,6 +196,7 @@ +
    diff --git a/core/views.py b/core/views.py index 62feee8..e2e24b2 100644 --- a/core/views.py +++ b/core/views.py @@ -1,3 +1,5 @@ +from django.utils.dateparse import parse_date +from datetime import datetime, time, timedelta import base64 import re import urllib.parse @@ -1277,6 +1279,12 @@ def log_door_visit(request): 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', '') + redirect_url = reverse('door_visits') + if next_qs: + redirect_url += f"?{next_qs}" + # Get the volunteer linked to the current user volunteer = Volunteer.objects.filter(user=request.user, tenant=tenant).first() @@ -1317,7 +1325,7 @@ def log_door_visit(request): if not voters.exists(): messages.warning(request, f"No targeted voters found at {address_street}.") - return redirect('door_visits') + return redirect(redirect_url) for voter in voters: # 1) Update voter flags @@ -1347,8 +1355,7 @@ def log_door_visit(request): else: messages.error(request, "There was an error in the visit log form.") - return redirect('door_visits') - + return redirect(redirect_url) def door_visit_history(request): """ @@ -1360,17 +1367,39 @@ def door_visit_history(request): return redirect("index") tenant = get_object_or_404(Tenant, id=selected_tenant_id) - # Get all "Door Visit" interactions for this tenant, ordered by date desc + # Date filter + start_date = request.GET.get("start_date") + end_date = request.GET.get("end_date") + + # Get all "Door Visit" interactions for this tenant interactions = Interaction.objects.filter( voter__tenant=tenant, type__name="Door Visit" - ).select_related('voter', 'volunteer').order_by('-date') + ).select_related("voter", "volunteer") + if start_date or end_date: + try: + if start_date: + d = parse_date(start_date) + if d: + start_dt = timezone.make_aware(datetime.combine(d, time.min)) + interactions = interactions.filter(date__gte=start_dt) + if end_date: + d = parse_date(end_date) + if d: + # Use lt with next day to capture everything on the end_date + end_dt = timezone.make_aware(datetime.combine(d + timedelta(days=1), time.min)) + interactions = interactions.filter(date__lt=end_dt) + except Exception as e: + logger.error(f"Error filtering door visit history by date: {e}") + + # Summary of counts per volunteer # Grouping by household (unique address) visited_households = {} - for interaction in interactions: + volunteer_counts = {} + + for interaction in interactions.order_by("-date"): v = interaction.voter - # Use concatenated address if available, otherwise build it addr = v.address.strip() if v.address else f"{v.address_street}, {v.city}, {v.state} {v.zip_code}".strip(", ") if not addr: continue @@ -1378,38 +1407,43 @@ def door_visit_history(request): key = addr.lower() if key not in visited_households: + # Calculate volunteer summary - only once per household + v_obj = interaction.volunteer + v_name = f"{v_obj.first_name} {v_obj.last_name}".strip() or v_obj.email if v_obj else "N/A" + volunteer_counts[v_name] = volunteer_counts.get(v_name, 0) + 1 + visited_households[key] = { - 'address_display': addr, - 'address_street': v.address_street, - 'city': v.city, - 'state': v.state, - 'zip_code': v.zip_code, - 'neighborhood': v.neighborhood, - 'district': v.district, - 'last_visit_date': interaction.date, - 'last_outcome': interaction.description, - 'voters_at_address': set(), - 'interaction_count': 0, - 'latest_interaction': interaction + "address_display": addr, + "address_street": v.address_street, + "city": v.city, + "state": v.state, + "zip_code": v.zip_code, + "neighborhood": v.neighborhood, + "district": v.district, + "last_visit_date": interaction.date, + "last_outcome": interaction.description, + "last_volunteer": interaction.volunteer, + "notes": interaction.notes, + "voters_at_address": set(), + "latest_interaction": interaction } - visited_households[key]['voters_at_address'].add(f"{v.first_name} {v.last_name}") - visited_households[key]['interaction_count'] += 1 - - if interaction.date > visited_households[key]['last_visit_date']: - visited_households[key]['last_visit_date'] = interaction.date - visited_households[key]['last_outcome'] = interaction.description - visited_households[key]['latest_interaction'] = interaction + visited_households[key]["voters_at_address"].add(f"{v.first_name} {v.last_name}") + + # Sort volunteer counts by total (descending) + sorted_volunteer_counts = sorted(volunteer_counts.items(), key=lambda x: x[1], reverse=True) history_list = list(visited_households.values()) - history_list.sort(key=lambda x: x['last_visit_date'], reverse=True) + history_list.sort(key=lambda x: x["last_visit_date"], reverse=True) paginator = Paginator(history_list, 50) - page_number = request.GET.get('page') + page_number = request.GET.get("page") history_page = paginator.get_page(page_number) context = { - 'selected_tenant': tenant, - 'history': history_page, + "selected_tenant": tenant, + "history": history_page, + "start_date": start_date, "end_date": end_date, + "volunteer_counts": sorted_volunteer_counts, } - return render(request, 'core/door_visit_history.html', context) + return render(request, "core/door_visit_history.html", context) diff --git a/core_view_fix.tmp b/core_view_fix.tmp new file mode 100644 index 0000000..b04ef99 --- /dev/null +++ b/core_view_fix.tmp @@ -0,0 +1,14 @@ +context = { + 'selected_tenant': tenant, + 'households': households_page, + 'district_filter': district_filter, + 'neighborhood_filter': neighborhood_filter, + 'address_filter': address_filter, + 'map_data_json': json.dumps(map_data), + 'google_maps_api_key': getattr(settings, 'GOOGLE_MAPS_API_KEY', ''), + 'visit_form': DoorVisitLogForm(), + } + return render(request, 'core/door_visits.html', context) + +def log_door_visit(request): + """ \ No newline at end of file