Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create models and serializers for AreaSearchStatus #503

Merged
merged 1 commit into from
Jul 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions plotsearch/migrations/0026_areasearchstatus.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Generated by Django 3.2.13 on 2023-07-26 07:39

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import enumfields.fields
import plotsearch.enums


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("plotsearch", "0025_directreservationlink"),
]

operations = [
migrations.CreateModel(
name="AreaSearchStatus",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"decline_reason",
enumfields.fields.EnumField(
blank=True,
enum=plotsearch.enums.DeclineReason,
max_length=30,
null=True,
),
),
("preparer_note", models.TextField(blank=True, null=True)),
],
),
migrations.CreateModel(
name="AreaSearchStatusNote",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("time_stamp", models.DateTimeField(auto_created=True)),
("note", models.TextField()),
(
"area_search_status",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="status_notes",
to="plotsearch.areasearchstatus",
),
),
(
"preparer",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="+",
to=settings.AUTH_USER_MODEL,
),
),
],
),
migrations.AddField(
model_name="areasearch",
name="area_search_status",
field=models.OneToOneField(
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="area_search",
to="plotsearch.areasearchstatus",
),
),
]
21 changes: 21 additions & 0 deletions plotsearch/models/plot_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,11 @@ def areasearch_id_generator():
return "{}-{:05d}".format(beginning_str, identifier)


class AreaSearchStatus(models.Model):
decline_reason = EnumField(DeclineReason, max_length=30, null=True, blank=True)
preparer_note = models.TextField(blank=True, null=True)


class AreaSearch(models.Model):
# In Finnish: aluehaku

Expand Down Expand Up @@ -444,6 +449,13 @@ class AreaSearch(models.Model):
on_delete=models.PROTECT,
)

area_search_status = models.OneToOneField(
AreaSearchStatus,
on_delete=models.CASCADE,
related_name="area_search",
null=True,
)


def get_area_search_attachment_upload_to(instance, filename):
return "/".join(
Expand Down Expand Up @@ -473,6 +485,15 @@ class AreaSearchAttachment(NameModel):
)


class AreaSearchStatusNote(models.Model):
note = models.TextField()
preparer = models.ForeignKey(User, on_delete=models.CASCADE, related_name="+")
time_stamp = models.DateTimeField(auto_created=True)
area_search_status = models.ForeignKey(
AreaSearchStatus, on_delete=models.CASCADE, related_name="status_notes"
)


class DirectReservationLink(models.Model):
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
targets = models.ManyToManyField(PlotSearchTarget)
Expand Down
139 changes: 135 additions & 4 deletions plotsearch/serializers/plot_search.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import requests
from django.core.exceptions import BadRequest
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from enumfields.drf import EnumSupportSerializerMixin
from pyproj import Proj, transform
Expand All @@ -9,7 +10,7 @@
from field_permissions.serializers import FieldPermissionsSerializerMixin
from forms.models import Form
from forms.serializers.form import AnswerSerializer, FormSerializer
from leasing.models import Decision, PlanUnit
from leasing.models import Decision, PlanUnit, Plot
from leasing.models.land_area import CustomDetailedPlan
from leasing.serializers.decision import DecisionSerializer
from leasing.serializers.land_area import (
Expand All @@ -36,7 +37,12 @@
PlotSearchType,
)
from plotsearch.models.info_links import TargetInfoLink
from plotsearch.models.plot_search import AreaSearchAttachment, DirectReservationLink
from plotsearch.models.plot_search import (
AreaSearchAttachment,
AreaSearchStatus,
AreaSearchStatusNote,
DirectReservationLink,
)
from plotsearch.serializers.info_links import PlotSearchTargetInfoLinkSerializer
from plotsearch.utils import (
get_applicant,
Expand Down Expand Up @@ -726,7 +732,57 @@ def create(self, validated_data):
return attachment


class AreaSearchSerializer(serializers.ModelSerializer):
class AreaSearchStatusNoteSerializer(serializers.ModelSerializer):
preparer = UserSerializer(read_only=True)
time_stamp = serializers.DateTimeField(read_only=True)

class Meta:
model = AreaSearchStatusNote
fields = (
"preparer",
"note",
"time_stamp",
)


class AreaSearchStatusSerializer(
EnumSupportSerializerMixin, serializers.ModelSerializer
):
status_notes = AreaSearchStatusNoteSerializer(required=False, many=True)

class Meta:
model = AreaSearchStatus
fields = (
"decline_reason",
"status_notes",
"preparer_note",
)

def create_area_status_note(self, instance, status_note):
if isinstance(status_note, list) and len(status_note) != 0:
note = status_note[0].get("note", None)
if note is not None:
AreaSearchStatusNote.objects.create(
preparer=self.context["request"].user,
note=note,
time_stamp=timezone.now(),
area_search_status=instance,
)

def create(self, validated_data):
status_note = validated_data.pop("status_notes", None)
instance = super().create(validated_data)
self.create_area_status_note(instance, status_note)
return instance

def update(self, instance, validated_data):
status_note = validated_data.pop("status_notes", None)
instance = super().update(instance, validated_data)
self.create_area_status_note(instance, status_note)
return instance


class AreaSearchSerializer(EnumSupportSerializerMixin, serializers.ModelSerializer):
id = serializers.IntegerField(read_only=True)
form = InstanceDictPrimaryKeyRelatedField(
instance_class=Form,
Expand All @@ -752,6 +808,14 @@ class AreaSearchSerializer(serializers.ModelSerializer):
many=True,
)

preparer = InstanceDictPrimaryKeyRelatedField(
instance_class=User,
queryset=User.objects.all(),
related_serializer=UserSerializer,
required=False,
)
area_search_status = AreaSearchStatusSerializer(required=False, allow_null=True)

class Meta:
model = AreaSearch
fields = (
Expand All @@ -772,11 +836,12 @@ class Meta:
"identifier",
"state",
"received_date",
"answer",
"area_search_status",
)

def create(self, validated_data):
area_form_qs = Form.objects.filter(is_area_form=True)
area_search_status = validated_data.pop("area_search_status", None)
if area_form_qs.exists():
validated_data["form"] = area_form_qs.last()
else:
Expand Down Expand Up @@ -835,6 +900,12 @@ def create(self, validated_data):
attachment.area_search = area_search
attachment.save()

as_serializer = AreaSearchStatusSerializer(
data=area_search_status, context=self.context
)
if as_serializer.is_valid():
as_serializer.save()

return area_search

@staticmethod
Expand All @@ -844,9 +915,69 @@ def get_applicants(obj):
get_applicant(obj.answer, applicant_list)
return applicant_list

def update(self, instance, validated_data):
area_search_status = validated_data.pop("area_search_status", None)
instance = super().update(instance, validated_data)
area_search_status_qs = AreaSearchStatus.objects.filter(area_search=instance)
as_serializer = AreaSearchStatusSerializer(context=self.context)

if area_search_status_qs.exists():
area_search_status = as_serializer.update(
area_search_status_qs.get(), area_search_status
)
else:
area_search_status = as_serializer.create(area_search_status)

instance.area_search_status = area_search_status
instance.save()

return instance


class AreaSearchDetailSerializer(AreaSearchSerializer):
answer = AnswerSerializer(read_only=True, required=False)
plot = serializers.ListField(child=serializers.CharField(), read_only=True)

class Meta:
model = AreaSearch
fields = (
"id",
"form",
"applicants",
"start_date",
"end_date",
"geometry",
"description_area",
"description_intended_use",
"intended_use",
"area_search_attachments",
"address",
"district",
"preparer",
"lessor",
"identifier",
"state",
"received_date",
"area_search_status",
"answer",
"plot",
)

def to_representation(self, instance):
ret = super().to_representation(instance)
plot_identifiers = (
Plot.objects.filter(geometry__intersects=instance.geometry)
.values("identifier")
.distinct("identifier")
)
identifiers = list()
if plot_identifiers.exists():
for plot_identifier in plot_identifiers:
identifiers.append(plot_identifier["identifier"])
ret.update({"plot": identifiers})
else:
ret.update({"plot": None})
return ret


class InformationCheckSerializer(
Expand Down
36 changes: 35 additions & 1 deletion plotsearch/tests/api/test_plot_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,7 @@ def test_getting_and_editing_and_deleting_existing_info_link(


@pytest.mark.django_db
def test_area_search_detail(
def test_get_area_search_detail(
django_db_setup, admin_client, area_search_test_data,
):
url = reverse("areasearch-detail", kwargs={"pk": area_search_test_data.id})
Expand All @@ -632,6 +632,40 @@ def test_area_search_detail(
assert response.status_code == 200, "%s %s" % (response.status_code, response.data)


def test_post_area_search_detail(
django_db_setup, admin_client, area_search_test_data,
):
data = {
"area_search_status": {"status_notes": [{"note": "Aluetta ei saa vuokrata"}]}
}
url = reverse("areasearch-detail", kwargs={"pk": area_search_test_data.id})

response = admin_client.patch(url, data=data, content_type="application/json")
assert response.status_code == 200, "%s %s" % (response.status_code, response.data)


def test_post_area_search_detail_empty_payload(
django_db_setup, admin_client, area_search_test_data,
):
url = reverse("areasearch-detail", kwargs={"pk": area_search_test_data.id})
data = {"area_search_status": {}}

response = admin_client.patch(url, data=data, content_type="application/json")
assert response.status_code == 200, "%s %s" % (response.status_code, response.data)

data = {"area_search_status": {"status_notes": []}}
response = admin_client.patch(url, data=data, content_type="application/json")
assert response.status_code == 200, "%s %s" % (response.status_code, response.data)

data = {"area_search_status": {"status_notes": [{}]}}
response = admin_client.patch(url, data=data, content_type="application/json")
assert response.status_code == 200, "%s %s" % (response.status_code, response.data)

data = {"area_search_status": {"status_notes": [{"note": ""}]}}
response = admin_client.patch(url, data=data, content_type="application/json")
assert response.status_code == 400, "%s %s" % (response.status_code, response.data)


@pytest.mark.django_db
def test_area_search_list(django_db_setup, admin_client, area_search_test_data):

Expand Down
Loading