Skip to content

Commit

Permalink
Merge pull request #480 from deardurham/add_dob_to_client
Browse files Browse the repository at this point in the history
Add DOB to client
  • Loading branch information
georgehelman authored Jun 9, 2024
2 parents ec9d0a8 + d01e46e commit 424101e
Show file tree
Hide file tree
Showing 21 changed files with 632 additions and 79 deletions.
34 changes: 32 additions & 2 deletions dear_petition/petition/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from dear_petition.petition.models import (
CIPRSRecord,
Contact,
Client,
Batch,
Offense,
OffenseRecord,
Expand Down Expand Up @@ -147,6 +148,25 @@ class ClientSerializer(ContactSerializer):
state = serializers.CharField(required=True)
zipcode = serializers.CharField(required=True)
user = serializers.PrimaryKeyRelatedField(read_only=True)
batches = serializers.PrimaryKeyRelatedField(many=True, read_only=True)

class Meta:
model = Client
fields = [
"pk",
"name",
"category",
"address1",
"address2",
"formatted_address",
"city",
"state",
"zipcode",
"user",
"batches",
"county",
"dob",
]


class GeneratePetitionSerializer(serializers.Serializer):
Expand Down Expand Up @@ -288,7 +308,7 @@ class BatchSerializer(serializers.ModelSerializer):
petitions = PetitionSerializer(many=True, read_only=True)
generate_letter_errors = ValidationField(method_name='get_generate_errors_data', serializer=GenerateDocumentSerializer)
generate_summary_errors = ValidationField(method_name='get_generate_errors_data', serializer=GenerateDocumentSerializer)

def get_generate_errors_data(self, obj):
return {'batch': obj.pk}

Expand Down Expand Up @@ -316,9 +336,10 @@ class BatchDetailSerializer(serializers.ModelSerializer):
)
attorney = ContactSerializer(read_only=True)
client_id = serializers.PrimaryKeyRelatedField(
source='client', queryset=Contact.objects.filter(category='client'), write_only=True, required=False
source='client', queryset=Client.objects.all(), write_only=True, required=False
)
client = ClientSerializer(read_only=True)
client_errors = serializers.SerializerMethodField()

generate_letter_errors = ValidationField(method_name='get_generate_errors_data', serializer=GenerateDocumentSerializer)
generate_summary_errors = ValidationField(method_name='get_generate_errors_data', serializer=GenerateDocumentSerializer)
Expand All @@ -341,6 +362,7 @@ class Meta:
"client_id",
"generate_letter_errors",
"generate_summary_errors",
"client_errors"
]
read_only_fields = ["user", "pk", "date_uploaded", "records", "petitions"]

Expand All @@ -350,6 +372,14 @@ def get_petitions(self, instance):
batch=instance.pk,
).order_by("county", "jurisdiction")
return ParentPetitionSerializer(parent_petitions, many=True).data

def get_client_errors(self, instance):
errors = []
if not instance.client:
return errors
if not instance.client.dob:
errors.append("Date of birth missing. The petition generator will try its best to identify a date of birth from the records at time of petition creation.")
return errors


class MyInboxSerializer(serializers.ModelSerializer):
Expand Down
43 changes: 43 additions & 0 deletions dear_petition/petition/api/tests/test_batch.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import pytest
import datetime

from django.urls import reverse
from django.utils import timezone
from django.utils.datastructures import MultiValueDict

from rest_framework import status

from dear_petition.petition.tests.factories import BatchFactory, CIPRSRecordFactory, OffenseFactory, ClientFactory, OffenseRecordFactory

pytestmark = pytest.mark.django_db


Expand All @@ -29,3 +33,42 @@ def test_batch_post_multiple_files(api_client, fake_pdf, fake_pdf2, mock_import)
assert response.status_code == status.HTTP_201_CREATED
assert mock_import.assert_called_once
assert "id" in response.data

def test_adjust_for_new_client_dob():
"""Test that when a DOB is added or updated on the client, the batch is updated accordingly."""

batch = BatchFactory()
record = CIPRSRecordFactory(batch=batch, offense_date=datetime.date(2000,1,1), dob=None)
offense = OffenseFactory(ciprs_record=record, disposition_method="OTHER") # Conviction charge
offense_record = OffenseRecordFactory(
action="CONVICTED", offense=offense
)

client = ClientFactory(dob=timezone.now().date()) # Create a youngster
batch.client = client
batch.save()
batch.adjust_for_new_client_dob()

assert offense_record in batch.underaged_conviction_records()

batch.client.dob = datetime.date(1800,1,1) # Update the youngster to be an elder
batch.client.save()
batch.refresh_from_db() # adjust_for_new_client_dob should get automatically called in Client save
assert offense_record not in batch.underaged_conviction_records()

client = ClientFactory(dob=datetime.date(1800,1,1)) # Create an elder
batch.client = client
batch.save()
batch.adjust_for_new_client_dob()
assert offense_record not in batch.underaged_conviction_records()

batch.client.dob = timezone.now().date() # Update the elder to be a youngster
batch.client.save()
batch.refresh_from_db() # adjust_for_new_client_dob should get automatically called in Client save
assert offense_record in batch.underaged_conviction_records()

# try un-setting client to test default behavior when no DOB known
batch.client = None
batch.save()
batch.adjust_for_new_client_dob()
assert offense_record not in batch.underaged_conviction_records()
1 change: 1 addition & 0 deletions dear_petition/petition/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
router.register(r"offense", viewsets.OffenseViewSet)
router.register(r"offenserecord", viewsets.OffenseRecordViewSet)
router.register(r"contact", viewsets.ContactViewSet)
router.register(r"client", viewsets.ClientViewSet)
router.register(r"batch", viewsets.BatchViewSet)
router.register(r"petitions", viewsets.PetitionViewSet)
router.register(r"generatedpetition", viewsets.GeneratedPetitionViewSet)
Expand Down
30 changes: 30 additions & 0 deletions dear_petition/petition/api/viewsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,15 @@ def import_agencies(self, request):
resources.AgencyResource().import_data(dataset, raise_errors=True)
return Response({})

class ClientViewSet(ContactViewSet):
queryset = pm.Client.objects.all()
serializer_class = serializers.ClientSerializer

def get_serializer_class(self):
return serializers.ClientSerializer

def get_queryset(self):
return pm.Client.objects.filter(user=self.request.user)


class BatchViewSet(viewsets.ModelViewSet):
Expand Down Expand Up @@ -354,6 +363,27 @@ def combine_batches(self, request):

new_batch = combine_batches(batch_ids, label, user_id)
return Response(self.get_serializer(new_batch).data)

@action(
detail=True,
methods=[
"post",
],
)
def assign_client_to_batch(self, request, pk):
client_id = request.data['client_id']

try:
client = pm.Client.objects.get(pk=client_id)
except pm.Client.DoesNotExist:
return Response(
"Unknown client.", status=status.HTTP_400_BAD_REQUEST
)
batch = self.get_object()
batch.client = client
batch.save()
batch.adjust_for_new_client_dob()
return Response({"batch_id": batch.pk})


class MyInboxView(generics.ListAPIView):
Expand Down
2 changes: 2 additions & 0 deletions dear_petition/petition/conftest.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import string
from datetime import datetime

from django.utils import timezone
import pytest

from dear_petition.petition.constants import CHARGED, CONVICTED, FEMALE
Expand Down Expand Up @@ -164,6 +165,7 @@ def client():
city='Durham',
state='NC',
zipcode='27701',
dob = timezone.now().date() # I wasn't born yesterday
)


Expand Down
2 changes: 1 addition & 1 deletion dear_petition/petition/etl/load.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def create_petitions_from_records(batch, form_type):
)


def link_offense_records(petition, filter_active=True):
def link_offense_records(petition):
"""Divide offense records across petition and any needed attachment forms."""

offense_records = petition.get_all_offense_records()
Expand Down
75 changes: 53 additions & 22 deletions dear_petition/petition/etl/tests/test_transform.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import pytest
from django.utils import timezone

from dear_petition.petition import constants
from dear_petition.petition import models as pm
Expand All @@ -9,6 +10,7 @@
OffenseRecordFactory,
PetitionFactory,
CIPRSRecordFactory,
ClientFactory,
)
from dear_petition.petition.etl.load import link_offense_records, create_documents
from dear_petition.petition.etl.transform import recalculate_petitions, combine_batches
Expand All @@ -17,13 +19,12 @@


def test_recalculate_petitions(petition):
petition = PetitionFactory(form_type=constants.UNDERAGED_CONVICTIONS)
batch = petition.batch
record = CIPRSRecordFactory(
batch=batch, jurisdiction=constants.DISTRICT_COURT, county="DURHAM"
)
offense = OffenseFactory(
disposition_method="PROBATION OTHER",
disposition_method="Dismissed by Court",
ciprs_record=record,
jurisdiction=constants.DISTRICT_COURT,
)
Expand All @@ -48,35 +49,64 @@ def test_recalculate_petitions(petition):
assert not petition.has_attachments()




def test_combine_batches(batch, batch_file, fake_pdf):
record = CIPRSRecordFactory(
batch=batch, jurisdiction=constants.DISTRICT_COURT, county="DURHAM"
)
offense = OffenseFactory(
disposition_method="PROBATION OTHER",
ciprs_record=record,
jurisdiction=constants.DISTRICT_COURT,
)
offense_record = OffenseRecordFactory(offense=offense, action="CHARGED")
record.refresh_record_from_data()

second_batch = BatchFactory()

second_record_data = {
"General": {"County": "DURHAM", "File No": "00GR000001"},
"Case Information": {
"Case Status": "DISPOSED",
"Offense Date": "2018-01-01T20:00:00",
},
"Defendant": {
"Date of Birth/Estimated Age": "1990-01-01",
"Name": "DOE,JON,BOJACK",
"Race": "WHITE",
"Sex": "MALE",
},
"District Court Offense Information": [
{
"Records": [
{
"Action": "CHARGED",
"Description": "SPEEDING(80 mph in a 65 mph zone)",
"Severity": "TRAFFIC",
"Law": "20-141(J1)",
"Code": "4450",
},
],
"Disposed On": "2018-02-01",
"Disposition Method": "DISPOSED BY JUDGE",
},
{
"Records": [
{
"Action": "CHARGED",
"Description": "SPEEDING(80 mph in a 65 mph zone)",
"Severity": "TRAFFIC",
"Law": "20-141(J1)",
"Code": "4450",
},
],
"Disposed On": "2018-02-01",
"Disposition Method": "DISPOSED BY JUDGE",
}
],
"Superior Court Offense Information": [],
}
second_batch_file = BatchFileFactory(batch=second_batch, file=fake_pdf)

second_record = CIPRSRecordFactory(
batch=second_batch, batch_file=second_batch_file, jurisdiction=constants.DISTRICT_COURT, county="DURHAM"
)
second_offense = OffenseFactory(
disposition_method="PROBATION OTHER",
ciprs_record=second_record,
jurisdiction=constants.DISTRICT_COURT,
)
OffenseRecordFactory(offense=second_offense, action="CHARGED")
third_offense = OffenseFactory(
disposition_method="PROBATION OTHER",
ciprs_record=second_record,
jurisdiction=constants.SUPERIOR_COURT,
batch=second_batch, data = second_record_data, batch_file=second_batch_file, jurisdiction=constants.DISTRICT_COURT, county="DURHAM"
)
OffenseRecordFactory(offense=third_offense, action="CHARGED")
second_record.refresh_record_from_data()

assert batch.records.count() == 1
assert pm.Offense.objects.filter(ciprs_record__batch__id=batch.id).count() == 1
Expand All @@ -88,7 +118,8 @@ def test_combine_batches(batch, batch_file, fake_pdf):
new_batch = combine_batches([batch.id, second_batch.id], label=new_label, user_id=user_id)

assert new_batch.records.count() == 2
assert pm.Offense.objects.filter(ciprs_record__batch__id=new_batch.id).count() == 2
assert pm.Offense.objects.filter(ciprs_record__batch__id=new_batch.id).count() == 3
assert pm.OffenseRecord.objects.filter(offense__ciprs_record__batch__id=new_batch.id).count() == 4
assert new_batch.files.count() == 2
assert new_batch.label == new_label
assert new_batch.user_id == user_id
Expand Down
Loading

0 comments on commit 424101e

Please sign in to comment.