diff --git a/core/__pycache__/forms.cpython-311.pyc b/core/__pycache__/forms.cpython-311.pyc index dd56483..fdd70b9 100644 Binary files a/core/__pycache__/forms.cpython-311.pyc and b/core/__pycache__/forms.cpython-311.pyc differ diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index 411f104..5bcaf3e 100644 Binary files a/core/__pycache__/models.cpython-311.pyc and b/core/__pycache__/models.cpython-311.pyc differ diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 645f02c..0f3b89b 100644 Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ diff --git a/core/forms.py b/core/forms.py index 99e08fd..90b9b8c 100644 --- a/core/forms.py +++ b/core/forms.py @@ -7,7 +7,7 @@ class VoterForm(forms.ModelForm): fields = [ 'first_name', 'last_name', 'nickname', 'birthdate', 'address_street', 'city', 'state', 'prior_state', 'zip_code', 'county', 'latitude', 'longitude', - 'phone', 'phone_type', 'email', 'voter_id', 'district', 'precinct', + 'phone', 'phone_type', 'secondary_phone', 'secondary_phone_type', 'email', 'voter_id', 'district', 'precinct', 'registration_date', 'is_targeted', 'candidate_support', 'yard_sign', 'window_sticker', 'notes' ] widgets = { @@ -32,6 +32,7 @@ class VoterForm(forms.ModelForm): self.fields['yard_sign'].widget.attrs.update({'class': 'form-select'}) self.fields['window_sticker'].widget.attrs.update({'class': 'form-select'}) self.fields['phone_type'].widget.attrs.update({'class': 'form-select'}) + self.fields['secondary_phone_type'].widget.attrs.update({'class': 'form-select'}) class AdvancedVoterSearchForm(forms.Form): MONTH_CHOICES = [ diff --git a/core/migrations/0027_voter_secondary_phone_voter_secondary_phone_type.py b/core/migrations/0027_voter_secondary_phone_voter_secondary_phone_type.py new file mode 100644 index 0000000..5ac9d53 --- /dev/null +++ b/core/migrations/0027_voter_secondary_phone_voter_secondary_phone_type.py @@ -0,0 +1,23 @@ +# Generated by Django 5.2.7 on 2026-01-29 18:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0026_alter_interaction_date'), + ] + + operations = [ + migrations.AddField( + model_name='voter', + name='secondary_phone', + field=models.CharField(blank=True, max_length=20), + ), + migrations.AddField( + model_name='voter', + name='secondary_phone_type', + field=models.CharField(choices=[('home', 'Home Phone'), ('cell', 'Cell Phone'), ('work', 'Work Phone')], default='cell', max_length=10), + ), + ] diff --git a/core/migrations/__pycache__/0027_voter_secondary_phone_voter_secondary_phone_type.cpython-311.pyc b/core/migrations/__pycache__/0027_voter_secondary_phone_voter_secondary_phone_type.cpython-311.pyc new file mode 100644 index 0000000..f09593c Binary files /dev/null and b/core/migrations/__pycache__/0027_voter_secondary_phone_voter_secondary_phone_type.cpython-311.pyc differ diff --git a/core/models.py b/core/models.py index b9e6253..e86ca70 100644 --- a/core/models.py +++ b/core/models.py @@ -149,6 +149,8 @@ class Voter(models.Model): longitude = models.DecimalField(max_digits=12, decimal_places=9, null=True, blank=True) phone = models.CharField(max_length=20, blank=True) phone_type = models.CharField(max_length=10, choices=PHONE_TYPE_CHOICES, default='cell') + secondary_phone = models.CharField(max_length=20, blank=True) + secondary_phone_type = models.CharField(max_length=10, choices=PHONE_TYPE_CHOICES, default="cell") email = models.EmailField(blank=True) district = models.CharField(max_length=100, blank=True, db_index=True) precinct = models.CharField(max_length=100, blank=True, db_index=True) @@ -222,6 +224,7 @@ class Voter(models.Model): def save(self, *args, **kwargs): # Auto-format phone number self.phone = format_phone_number(self.phone) + self.secondary_phone = format_phone_number(self.secondary_phone) # Ensure longitude is truncated to 12 characters before saving if self.longitude: diff --git a/core/templates/core/voter_advanced_search.html b/core/templates/core/voter_advanced_search.html index 82daeb3..8e39286 100644 --- a/core/templates/core/voter_advanced_search.html +++ b/core/templates/core/voter_advanced_search.html @@ -134,6 +134,12 @@ {% if voter.phone %}
{{ voter.get_phone_type_display }}
{% endif %} + {% if voter.secondary_phone %} +
+ {{ voter.secondary_phone }} +
{{ voter.get_secondary_phone_type_display }}
+
+ {% endif %} {% if voter.is_targeted %} diff --git a/core/templates/core/voter_detail.html b/core/templates/core/voter_detail.html index e862f4e..3e4c973 100644 --- a/core/templates/core/voter_detail.html +++ b/core/templates/core/voter_detail.html @@ -92,6 +92,13 @@ {{ voter.get_phone_type_display }} {% endif %} + {% if voter.secondary_phone %} +
  • + + {{ voter.secondary_phone }} + {{ voter.get_secondary_phone_type_display }} +
  • + {% endif %}
  • {{ voter.birthdate|date:"M d, Y"|default:"N/A" }} @@ -453,6 +460,14 @@ {{ voter_form.phone_type }} +
    + + {{ voter_form.secondary_phone }} +
    +
    + + {{ voter_form.secondary_phone_type }} +
    {{ voter_form.email }} diff --git a/core/templates/core/voter_list.html b/core/templates/core/voter_list.html index 7c97803..70a76e2 100644 --- a/core/templates/core/voter_list.html +++ b/core/templates/core/voter_list.html @@ -45,7 +45,12 @@
    {{ voter.address|default:"No address provided" }}
    {{ voter.district|default:"-" }} - {{ voter.phone|default:"-" }} + + {{ voter.phone|default:"-" }} + {% if voter.secondary_phone %} +
    {{ voter.secondary_phone }} + {% endif %} + {% if voter.is_targeted %} Yes diff --git a/core/views.py b/core/views.py index 43c2add..7013db4 100644 --- a/core/views.py +++ b/core/views.py @@ -531,14 +531,14 @@ def export_voters_csv(request): writer = csv.writer(response) writer.writerow([ 'Voter ID', 'First Name', 'Last Name', 'Nickname', 'Birthdate', - 'Address', 'City', 'State', 'Zip Code', 'Phone', 'Phone Type', 'Email', + 'Address', 'City', 'State', 'Zip Code', 'Phone', 'Phone Type', 'Secondary Phone', 'Secondary Phone Type', 'Email', 'District', 'Precinct', 'Is Targeted', 'Support', 'Yard Sign', 'Window Sticker', 'Notes' ]) for voter in voters: writer.writerow([ voter.voter_id, voter.first_name, voter.last_name, voter.nickname, voter.birthdate, - voter.address, voter.city, voter.state, voter.zip_code, voter.phone, voter.get_phone_type_display(), voter.email, + voter.address, voter.city, voter.state, voter.zip_code, voter.phone, voter.get_phone_type_display(), voter.secondary_phone, voter.get_secondary_phone_type_display(), voter.email, voter.district, voter.precinct, 'Yes' if voter.is_targeted else 'No', voter.get_candidate_support_display(), voter.get_yard_sign_display(), voter.get_window_sticker_display(), voter.notes ])