Skip to content

Commit

Permalink
Refactor data model & associated changes
Browse files Browse the repository at this point in the history
Refactor the clerk data model to better reflect how the data is used. Changes
made where in three major parts:

1. Migrate fields to a different model or add model fields:

   - Migrate tenancy foreign key field from client to issue model
   - Migrate weekly_rent field from client to issue model
   - Migrate weekly_income field from client to issue model
   - Migrate employment_status field from client to case model
   - Migrate rental_circumstances field from client to tenancy model
   - Migrate referrer & referrer_type fields from client to case model
   - Add preferred_name field to client model
   - Add pronouns field to client model

2. Update field choices:

   - Update issue model referrer_type field options
   - Update issue model employment_status field options
   - Update client model requires_interpreter field options
   - Update client model is_aboriginal_or_torres_strait_islander field options

   This might require data migration if, for example, the change is from a
   boolean to a char field type.

3. Update the business logic, tests etc. due to the model changes:

   - Update intake form submission
   - Update django admin interface
   - Update model serializers & factories
   - Update clerk frontend
   - Update tests
  • Loading branch information
luca-vari committed Feb 5, 2024
1 parent 3965444 commit 2f16caa
Show file tree
Hide file tree
Showing 55 changed files with 1,758 additions and 508 deletions.
19 changes: 8 additions & 11 deletions app/case/serializers/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@
from core.models import Client
from core.models.client import (
CallTime,
ReferrerType,
RentalType,
EligibilityCircumstanceType,
EmploymentType,
AboriginalOrTorresStraitIslander,
RequiresInterpreter,
)
from .fields import TextChoiceField, TextChoiceListField

Expand All @@ -19,23 +18,20 @@ class Meta:
"id",
"first_name",
"last_name",
"preferred_name",
"email",
"date_of_birth",
"phone_number",
"employment_status",
"weekly_income",
"gender",
"pronouns",
"centrelink_support",
"eligibility_notes",
"requires_interpreter",
"primary_language_non_english",
"primary_language",
"is_aboriginal_or_torres_strait_islander",
"rental_circumstances",
"number_of_dependents",
"eligibility_circumstances",
"referrer_type",
"referrer",
"age",
"full_name",
"notes",
Expand All @@ -50,11 +46,12 @@ class Meta:
date_of_birth = serializers.DateTimeField(
format="%d/%m/%Y", input_formats=["%d/%m/%Y"]
)
referrer_type = TextChoiceField(ReferrerType)
call_times = TextChoiceListField(CallTime)
employment_status = TextChoiceListField(EmploymentType)
eligibility_circumstances = TextChoiceListField(EligibilityCircumstanceType)
rental_circumstances = TextChoiceField(RentalType)
is_aboriginal_or_torres_strait_islander = TextChoiceField(
AboriginalOrTorresStraitIslander
)
requires_interpreter = TextChoiceField(RequiresInterpreter)

def get_url(self, obj):
return reverse("client-detail", args=(obj.pk,))
Expand Down
18 changes: 17 additions & 1 deletion app/case/serializers/issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,19 @@
from django.utils import timezone

from core.models import Issue, IssueNote
from core.models.issue import EmploymentType, ReferrerType
from accounts.models import User

from .user import UserSerializer
from .client import ClientSerializer
from .tenancy import TenancySerializer
from .person import PersonSerializer
from .fields import LocalTimeField, LocalDateField
from .fields import (
LocalTimeField,
LocalDateField,
TextChoiceField,
TextChoiceListField,
)


class IssueSerializer(serializers.ModelSerializer):
Expand All @@ -31,6 +38,12 @@ class Meta:
"lawyer",
"lawyer_id",
"client",
"tenancy",
"employment_status",
"weekly_income",
"weekly_rent",
"referrer_type",
"referrer",
"support_worker",
"support_worker_id",
"is_open",
Expand All @@ -48,6 +61,7 @@ class Meta:
lawyer = UserSerializer(read_only=True)
paralegal = UserSerializer(read_only=True)
client = ClientSerializer(read_only=True)
tenancy = TenancySerializer(read_only=True)
support_worker = PersonSerializer(read_only=True)
support_worker_id = serializers.IntegerField(write_only=True, allow_null=True)
paralegal_id = serializers.PrimaryKeyRelatedField(
Expand All @@ -64,6 +78,8 @@ class Meta:
outcome_display = serializers.CharField(source="get_outcome_display")
stage_display = serializers.CharField(source="get_stage_display")
created_at = LocalDateField()
employment_status = TextChoiceListField(EmploymentType)
referrer_type = TextChoiceField(ReferrerType)
url = serializers.SerializerMethodField()
# Case review fields.
is_conflict_check = serializers.SerializerMethodField()
Expand Down
9 changes: 4 additions & 5 deletions app/case/serializers/tenancy.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
from rest_framework import serializers
from django.urls import reverse

from core.models.tenancy import Tenancy, LeaseType
from .client import ClientSerializer
from core.models.tenancy import Tenancy, LeaseType, RentalType
from .person import PersonSerializer
from .fields import DateField, TextChoiceField
from .fields import TextChoiceField


class TenancySerializer(serializers.ModelSerializer):
Expand All @@ -17,21 +16,21 @@ class Meta:
"postcode",
"started",
"is_on_lease",
"rental_circumstances",
"landlord",
"agent",
"landlord_id",
"agent_id",
"client",
"url",
)

client = ClientSerializer(read_only=True)
landlord = PersonSerializer(read_only=True)
agent = PersonSerializer(read_only=True)
landlord_id = serializers.IntegerField(write_only=True, allow_null=True)
agent_id = serializers.IntegerField(write_only=True, allow_null=True)
url = serializers.SerializerMethodField()
is_on_lease = TextChoiceField(LeaseType, allow_blank=True)
rental_circumstances = TextChoiceField(RentalType)
started = serializers.DateTimeField(format="%d/%m/%Y", input_formats=["%d/%m/%Y"])

def get_url(self, obj):
Expand Down
57 changes: 57 additions & 0 deletions app/case/templates/case/tenancy_detail.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{% extends "case/_base.html" %}
{% block title %}Tenancy{% endblock %}

{% block content %}

<div class="ui container">
<h1 class="ui header">
Tenancy
<div class="sub header">
Created {{ tenancy.created_at|date:"jS M 'y" }}, updated {{ tenancy.modified_at|date:"jS M 'y" }}
</div>
</h1>

<h2 class="ui header">Property details</h2>
{{ forms.form }}

<h2 class="ui header">Property people</h2>
<table class="ui definition table small">
<tbody>
<tr>
<td class="three wide">Client</td>
<td>
<a href="{% url 'client-detail' client.pk %}">
{{ client.get_full_name|title }}
</a>
</td>
</tr>
<tr>
<td class="three wide">Agent</td>
<td>
{% if tenancy.agent %}
<a href="{% url 'person-detail' tenancy.agent.pk %}">
{{ tenancy.agent.full_name|title }}
</a>
{% else %}
No agent
{% endif %}
</td>
</tr>
<tr>
<td class="three wide">Landlord</td>
<td>
{% if tenancy.landlord %}
<a href="{% url 'person-detail' tenancy.landlord.pk %}">
{{ tenancy.landlord.full_name|title }}
</a>
{% else %}
No landlord
{% endif %}
</td>
</tr>
</tbody>
</table>
</div>


{% endblock %}
4 changes: 1 addition & 3 deletions app/case/tests/specific_view_tests/test_case_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ def test_case_list_view__search(superuser_client: APIClient):
def test_case_get_view(superuser_client: APIClient):
issue = factories.IssueFactory()
factories.IssueNoteFactory(issue=issue)
factories.TenancyFactory(client=issue.client)
url = reverse("case-api-detail", args=(issue.pk,))
response = superuser_client.get(url)
assert response.status_code == 200
Expand All @@ -165,7 +164,6 @@ def test_case_get_view__as_paralegal(
user.groups.set([paralegal_group])
annotate_group_access(user)
issue = factories.IssueFactory()
tenancy = factories.TenancyFactory(client=issue.client)
# Should be visible to a paralegal
issue_note_a = factories.IssueNoteFactory(issue=issue, note_type="PARALEGAL")
# Should be hidden from to a paralegal
Expand All @@ -184,7 +182,7 @@ def test_case_get_view__as_paralegal(
resp_data = response.json()

assert resp_data["issue"]["id"] == str(issue.pk)
assert resp_data["tenancy"]["id"] == tenancy.pk
assert resp_data["tenancy"]["id"] == issue.tenancy.pk
notes = resp_data["notes"]
assert len(notes) == 1
assert notes[0]["id"] == issue_note_a.pk
Expand Down
4 changes: 2 additions & 2 deletions app/case/tests/specific_view_tests/test_tenancy_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ def test_tenancy_view_object_permissions(
user, user_client: APIClient, paralegal_group, coordinator_group
):
client = ClientFactory()
issue = IssueFactory(client=client)
tenancy = TenancyFactory(client=client)
tenancy = TenancyFactory()
issue = IssueFactory(client=client, tenancy=tenancy)
url = reverse("tenancy-api-detail", args=(tenancy.pk,))

# Coordinator can access
Expand Down
5 changes: 2 additions & 3 deletions app/case/views/case.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def get_permissions(self):
def get_queryset(self):
user = self.request.user
queryset = (
Issue.objects.select_related("client")
Issue.objects.select_related("client", "tenancy")
.prefetch_related("paralegal__groups", "lawyer__groups")
.order_by("-created_at")
)
Expand Down Expand Up @@ -216,8 +216,7 @@ def retrieve(self, request, *args, **kwargs):
note_data = IssueNoteSerializer(notes, many=True).data

# Get tenancy data
tenancy = issue.client.tenancy_set.first()
tenancy_data = TenancySerializer(tenancy).data
tenancy_data = TenancySerializer(issue.tenancy).data

# Return composite response
response_data = {
Expand Down
2 changes: 1 addition & 1 deletion app/case/views/person.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def person_detail_page_view(request, pk):
except Person.DoesNotExist:
raise Http404()

q_filter = Q(client__tenancy__agent=person) | Q(client__tenancy__landlord=person)
q_filter = Q(tenancy__agent=person) | Q(tenancy__landlord=person)
issues = Issue.objects.filter(q_filter).order_by("-created_at").all()

context = {
Expand Down
10 changes: 8 additions & 2 deletions app/case/views/tenancy.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from rest_framework.mixins import UpdateModelMixin, RetrieveModelMixin

from case.utils.react import render_react_page
from case.serializers import TenancySerializer
from case.serializers import TenancySerializer, IssueSerializer
from core.models import Tenancy
from .auth import (
paralegal_or_better_required,
Expand All @@ -26,7 +26,13 @@ def tenancy_detail_page_view(request, pk):
if not (has_object_permission or request.user.is_coordinator_or_better):
raise PermissionDenied()

context = {"tenancy": TenancySerializer(instance=tenancy).data}
context = {
"tenancy": TenancySerializer(instance=tenancy).data,
"issues": IssueSerializer(
tenancy.issue_set.all(), read_only=True, many=True
).data,
}

return render_react_page(request, "Tenancy", "tenancy-detail", context)


Expand Down
7 changes: 3 additions & 4 deletions app/core/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,8 @@ class ClientAdmin(admin.ModelAdmin):
"last_name",
"email",
"phone_number",
"referrer_type",
"referrer",
"created_at",
)
list_filter = ("referrer_type",)


@admin.register(Issue)
Expand All @@ -100,9 +97,11 @@ class IssueAdmin(admin.ModelAdmin):
"is_alert_sent",
"is_case_sent",
"is_sharepoint_set_up",
"referrer_type",
"referrer",
"created_at",
)
list_filter = ("topic", "is_alert_sent", "is_case_sent")
list_filter = ("topic", "is_alert_sent", "is_case_sent", "referrer_type")

list_select_related = ("client",)

Expand Down
2 changes: 1 addition & 1 deletion app/core/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ class TenancyFactory(TimestampedModelFactory):
class Meta:
model = Tenancy

client = factory.SubFactory(ClientFactory)
agent = factory.SubFactory(PersonFactory)
landlord = factory.SubFactory(PersonFactory)
address = factory.Faker("address")
Expand All @@ -101,6 +100,7 @@ class Meta:
topic = "REPAIRS"
answers = {}
client = factory.SubFactory(ClientFactory)
tenancy = factory.SubFactory(TenancyFactory)
stage = "UNSTARTED"
is_sharepoint_set_up = True

Expand Down
18 changes: 18 additions & 0 deletions app/core/migrations/0055_client_preferred_name.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.0.10 on 2023-11-23 04:41

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('core', '0054_remove_issueevent_event_types_alter_issue_topic_and_more'),
]

operations = [
migrations.AddField(
model_name='client',
name='preferred_name',
field=models.CharField(blank=True, max_length=150, null=True),
),
]
18 changes: 18 additions & 0 deletions app/core/migrations/0056_client_pronouns.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.0.10 on 2023-11-24 01:19

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('core', '0055_client_preferred_name'),
]

operations = [
migrations.AddField(
model_name='client',
name='pronouns',
field=models.CharField(blank=True, max_length=32),
),
]
22 changes: 22 additions & 0 deletions app/core/migrations/0057_issue_tenancy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Generated by Django 4.0.10 on 2023-11-27 02:45

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):
dependencies = [
("core", "0056_client_pronouns"),
]

operations = [
migrations.AddField(
model_name="issue",
name="tenancy",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
to="core.tenancy",
),
),
]
Loading

0 comments on commit 2f16caa

Please sign in to comment.