Fakultas Ilmu Komputer UI

Commit 1c7f17d2 authored by Dave Nathanael's avatar Dave Nathanael
Browse files

Merge branch 'pbi-monitoring-case' into 'staging'

Reimplement MonitoringCase

See merge request !32
parents 4f33b8f5 0a4f1e8a
Pipeline #40379 passed with stages
in 4 minutes and 31 seconds
......@@ -3,10 +3,8 @@ from apps.cases.models import (
CaseSubject,
InvestigationCase,
MonitoringCase,
PositiveCase,
)
admin.site.register(CaseSubject)
admin.site.register(InvestigationCase)
admin.site.register(MonitoringCase)
admin.site.register(PositiveCase)
......@@ -4,7 +4,6 @@ from apps.cases.models import (
CaseSubject,
InvestigationCase,
MonitoringCase,
PositiveCase,
)
......@@ -20,16 +19,6 @@ class CaseSubjectFilter(FilterSet):
]
class PositiveCaseFilter(FilterSet):
class Meta:
model = PositiveCase
fields = [
"case_subject_id",
"outcome",
"author",
]
class InvestigationCaseFilter(FilterSet):
class Meta:
model = InvestigationCase
......@@ -50,12 +39,10 @@ class MonitoringCaseFilter(FilterSet):
model = MonitoringCase
fields = [
"investigation_case_id",
"positive_case_id",
"is_referred",
"is_checked",
"is_regularly_treated",
"regular_medicine_intake",
"treatment_start_date",
"treatment_end_date",
"outcome",
"author",
]
# Generated by Django 3.0.1 on 2020-04-13 14:02
from django.db import migrations, models
import uuid
class Migration(migrations.Migration):
dependencies = [
('cases', '0001_initial'),
]
operations = [
migrations.RemoveField(
model_name='monitoringcase',
name='positive_case_id',
),
migrations.AddField(
model_name='investigationcase',
name='outcome',
field=models.CharField(blank=True, max_length=256, null=True),
),
migrations.AlterField(
model_name='casesubject',
name='subject_id',
field=models.UUIDField(default=uuid.uuid4, editable=False),
),
migrations.AlterField(
model_name='investigationcase',
name='case_id',
field=models.UUIDField(default=uuid.uuid4, editable=False),
),
migrations.AlterField(
model_name='monitoringcase',
name='case_id',
field=models.UUIDField(default=uuid.uuid4, editable=False),
),
migrations.DeleteModel(
name='PositiveCase',
),
]
# Generated by Django 3.0.1 on 2020-04-14 07:53
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cases', '0002_auto_20200413_2102'),
]
operations = [
migrations.RemoveField(
model_name='monitoringcase',
name='checking_date',
),
migrations.RemoveField(
model_name='monitoringcase',
name='is_regularly_treated',
),
migrations.RemoveField(
model_name='monitoringcase',
name='outcome',
),
migrations.AddField(
model_name='monitoringcase',
name='regular_medicine_intake',
field=models.TextField(default='[]'),
),
]
......@@ -47,47 +47,6 @@ class CaseSubject(models.Model):
self.save()
class PositiveCase(models.Model):
revision_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
case_id = models.UUIDField(default=uuid.uuid4, editable=False)
case_subject_id = models.UUIDField(blank=True, null=True)
outcome = models.CharField(max_length=256)
author = models.ForeignKey(
Account,
blank=True,
null=True,
on_delete=models.DO_NOTHING,
related_name="positive_case",
)
deleted_at = models.DateTimeField(blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
is_active = models.BooleanField(default=True, db_index=True)
objects = SoftObjectManager()
class Meta:
db_table = "positive_case"
verbose_name_plural = "positive cases"
ordering = ["-created_at"]
def __str__(self):
if self.is_active:
return f"[Active] Rev. {self.revision_id} | by {self.author}"
return f"[Inactive] Rev. {self.revision_id} | by {self.author}"
def delete(self):
if self.deleted_at is None:
self.is_active = False
self.deleted_at = datetime.now(tz=pytz.timezone(TIMEZONE))
self.save()
@property
def case_subject(self):
return CaseSubject.objects.filter(
is_active=True, deleted_at__isnull=True, subject_id=self.case_subject_id
).first()
class InvestigationCase(models.Model):
revision_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
case_id = models.UUIDField(default=uuid.uuid4, editable=False)
......@@ -98,6 +57,7 @@ class InvestigationCase(models.Model):
risk_factors = models.TextField(default="{}")
is_referral_needed = models.BooleanField(db_index=True)
medical_facility_reference = models.CharField(max_length=128, blank=True)
outcome = models.CharField(max_length=256, blank=True, null=True)
author = models.ForeignKey(
Account,
blank=True,
......@@ -129,7 +89,7 @@ class InvestigationCase(models.Model):
@property
def reference_case(self):
return PositiveCase.objects.filter(
return InvestigationCase.objects.filter(
is_active=True, deleted_at__isnull=True, case_id=self.reference_case_id
).first()
......@@ -144,14 +104,11 @@ class MonitoringCase(models.Model):
revision_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
case_id = models.UUIDField(default=uuid.uuid4, editable=False)
investigation_case_id = models.UUIDField(blank=True, null=True)
positive_case_id = models.UUIDField(blank=True, null=True)
is_referred = models.BooleanField(blank=True, null=True, db_index=True)
is_checked = models.BooleanField(blank=True, null=True, db_index=True)
checking_date = models.DateField(blank=True, null=True)
is_regularly_treated = models.BooleanField(blank=True, null=True, db_index=True)
regular_medicine_intake = models.TextField(default="[]")
treatment_start_date = models.DateField(blank=True, null=True)
treatment_end_date = models.DateField(blank=True, null=True)
outcome = models.CharField(max_length=128, blank=True)
author = models.ForeignKey(
Account,
blank=True,
......@@ -182,12 +139,6 @@ class MonitoringCase(models.Model):
def clean(self):
super(MonitoringCase, self).clean()
reference_cases = [self.positive_case_id, self.investigation_case_id]
if sum([case is not None for case in reference_cases]) > 1:
raise ValidationError(
"Monitoring Case should refer to only 1 type of case (Investigation|Positive)"
)
def delete(self):
if self.deleted_at is None:
self.is_active = False
......@@ -199,9 +150,3 @@ class MonitoringCase(models.Model):
return InvestigationCase.objects.filter(
is_active=True, deleted_at__isnull=True, case_id=self.investigation_case_id
).first()
@property
def positive_case(self):
return PositiveCase.objects.filter(
is_active=True, deleted_at__isnull=True, case_id=self.positive_case_id
).first()
......@@ -5,7 +5,6 @@ from apps.cases.models import (
CaseSubject,
InvestigationCase,
MonitoringCase,
PositiveCase,
)
......@@ -27,43 +26,6 @@ class CaseSubjectSerializer(serializers.ModelSerializer):
]
class PositiveCaseSerializer(serializers.ModelSerializer):
is_active = serializers.BooleanField(read_only=True)
class Meta:
model = PositiveCase
fields = [
"revision_id",
"case_id",
"case_subject_id",
"outcome",
"is_active",
]
class PositiveCaseSummarySerializer(serializers.ModelSerializer):
case_subject = serializers.SerializerMethodField()
is_active = serializers.BooleanField(read_only=True)
author = AccountSerializer()
class Meta:
model = PositiveCase
fields = [
"revision_id",
"case_id",
"case_subject_id",
"case_subject",
"outcome",
"author",
"is_active",
]
def get_case_subject(self, instance):
case_subject = instance.case_subject
if case_subject:
return CaseSubjectSerializer(case_subject).data
class InvestigationCaseSerializer(serializers.ModelSerializer):
is_active = serializers.BooleanField(read_only=True)
......@@ -115,7 +77,7 @@ class InvestigationCaseSummarySerializer(serializers.ModelSerializer):
def get_reference_case(self, instance):
reference_case = instance.reference_case
if reference_case:
return PositiveCaseSerializer(reference_case).data
return InvestigationCaseSerializer(reference_case).data
class MonitoringCaseSerializer(serializers.ModelSerializer):
......@@ -127,20 +89,17 @@ class MonitoringCaseSerializer(serializers.ModelSerializer):
"revision_id",
"case_id",
"investigation_case_id",
"positive_case_id",
"is_referred",
"is_checked",
"is_regularly_treated",
"regular_medicine_intake",
"treatment_start_date",
"treatment_end_date",
"outcome",
"is_active",
]
class MonitoringCaseSummarySerializer(serializers.ModelSerializer):
investigation_case = serializers.SerializerMethodField()
positive_case = serializers.SerializerMethodField()
is_active = serializers.BooleanField(read_only=True)
author = AccountSerializer()
......@@ -151,14 +110,11 @@ class MonitoringCaseSummarySerializer(serializers.ModelSerializer):
"case_id",
"investigation_case_id",
"investigation_case",
"positive_case_id",
"positive_case",
"is_referred",
"is_checked",
"is_regularly_treated",
"regular_medicine_intake",
"treatment_start_date",
"treatment_end_date",
"outcome",
"author",
"is_active",
]
......@@ -167,8 +123,3 @@ class MonitoringCaseSummarySerializer(serializers.ModelSerializer):
investigation_case = instance.investigation_case
if investigation_case:
return InvestigationCaseSerializer(investigation_case).data
def get_positive_case(self, instance):
positive_case = instance.positive_case
if positive_case:
return PositiveCaseSerializer(positive_case).data
from apps.cases.models import (
CaseSubject,
InvestigationCase,
PositiveCase,
MonitoringCase,
)
......@@ -15,14 +14,6 @@ import factory
faker = Faker()
class PositiveCaseFactory(factory.DjangoModelFactory):
class Meta:
model = PositiveCase
author = factory.SubFactory(AccountFactory)
outcome = "Positive"
class InvestigationCaseFactory(factory.DjangoModelFactory):
class Meta:
model = InvestigationCase
......@@ -38,4 +29,3 @@ class MonitoringCaseFactory(factory.DjangoModelFactory):
model = MonitoringCase
author = factory.SubFactory(AccountFactory)
outcome = "Positive"
......@@ -6,12 +6,9 @@ from rest_framework.authtoken.models import Token
from rest_framework.test import APITestCase, APIClient
from apps.accounts.tests.factories.accounts import AccountFactory, UserFactory
from apps.cases.models import PositiveCase, InvestigationCase
from apps.cases.models import InvestigationCase
from apps.cases.tests.factories.case_subjects import CaseSubjectFactory
from apps.cases.tests.factories.cases import (
PositiveCaseFactory,
InvestigationCaseFactory,
)
from apps.cases.tests.factories.cases import InvestigationCaseFactory
from apps.constants import (
HEADER_PREFIX,
......@@ -26,14 +23,17 @@ class InvestigationCaseViewTest(APITestCase):
@classmethod
def setUpTestData(self):
self.BASE_URL = "/cases/investigation-cases/"
self.BASE_POSITIVE_URL = "/cases/investigation-cases/positive-cases/"
self.user_1 = UserFactory(username="user_1", password="justpass")
self.author = AccountFactory(user=self.user_1, admin=True)
self.token_1, _ = Token.objects.get_or_create(user=self.user_1)
self.case_subject = CaseSubjectFactory()
self.reference_case = PositiveCaseFactory(
case_subject_id=self.case_subject.subject_id, author=self.author,
self.reference_case = InvestigationCaseFactory(
case_subject_id=self.case_subject.subject_id,
author=self.author,
outcome="BTA+",
)
self.case = InvestigationCaseFactory(
author=self.author,
......@@ -97,6 +97,33 @@ class InvestigationCaseViewTest(APITestCase):
self.assertIn('"detail":"Invalid page."', response_string)
def test_list_positive_investigation_cases_success(self):
url = self.BASE_POSITIVE_URL
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
response_string = response.rendered_content.decode("utf-8")
self.assertIn('"count":1', response_string)
self.assertIn('"next":null', response_string)
self.assertIn('"previous":null', response_string)
self.assertIn(str(self.reference_case.revision_id), response_string)
self.assertIn(str(self.reference_case.case_id), response_string)
self.assertIn(str(self.reference_case.case_subject.revision_id), response_string)
self.assertIn(str(self.reference_case.case_subject.subject_id), response_string)
self.assertIn(str(self.reference_case.author.id), response_string)
def test_list_positive_investigation_case_paginate_failed(self):
url = self.BASE_POSITIVE_URL + "?page=100"
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
response_string = response.rendered_content.decode("utf-8")
self.assertIn('"detail":"Invalid page."', response_string)
def test_list_investigation_case_filter_success(self):
url = self.BASE_URL + "?risk_factors=" + self.case.risk_factors
......
......@@ -11,7 +11,6 @@ from apps.accounts.tests.factories.accounts import AccountFactory, UserFactory
from apps.cases.models import MonitoringCase
from apps.cases.tests.factories.case_subjects import CaseSubjectFactory
from apps.cases.tests.factories.cases import (
PositiveCaseFactory,
InvestigationCaseFactory,
MonitoringCaseFactory,
)
......@@ -34,11 +33,13 @@ class MonitoringCaseViewTest(APITestCase):
self.token, _ = Token.objects.get_or_create(user=self.user)
self.author = AccountFactory(user=self.user, admin=False)
self.case_subject = CaseSubjectFactory()
self.positive_case = PositiveCaseFactory(
author=self.author, case_subject_id=self.case_subject.subject_id,
self.positive_investigation_case = InvestigationCaseFactory(
author=self.author,
case_subject_id=self.case_subject.subject_id,
reference_case_id=None,
)
self.case_1 = MonitoringCaseFactory(
author=self.author, positive_case_id=self.positive_case.case_id,
author=self.author, investigation_case_id=self.positive_investigation_case.case_id,
)
self.investigation_case = InvestigationCaseFactory(
author=self.author,
......@@ -50,12 +51,12 @@ class MonitoringCaseViewTest(APITestCase):
)
self.other_deleted_case = MonitoringCaseFactory(
author=self.author,
positive_case_id=self.positive_case.case_id,
investigation_case_id=self.positive_investigation_case.case_id,
deleted_at=datetime.now(tz=pytz.timezone(TIMEZONE)),
)
self.inactive_case = MonitoringCaseFactory(
author=self.author,
positive_case_id=self.positive_case.case_id,
investigation_case_id=self.positive_investigation_case.case_id,
is_active=False,
)
......@@ -96,7 +97,7 @@ class MonitoringCaseViewTest(APITestCase):
self.assertIn('"detail":"Invalid page."', response_string)
def test_list_monitoring_case_filter_success(self):
url = self.BASE_URL + "?outcome=" + self.case_1.outcome
url = self.BASE_URL + "?is_checked=" + str(self.case_1.is_checked)
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
......@@ -106,7 +107,7 @@ class MonitoringCaseViewTest(APITestCase):
self.assertIn('"count":2', response_string)
def test_list_monitoring_case_filter_failed(self):
url = self.BASE_URL + "?outcome=1234567890"
url = self.BASE_URL + "?is_checked=False"
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
......@@ -133,8 +134,7 @@ class MonitoringCaseViewTest(APITestCase):
case_prev_all_count = MonitoringCase.objects.all().count()
data = {
"positive_case_id": str(self.positive_case.case_id),
"outcome": "Healed",
"investigation_case_id": str(self.positive_investigation_case.case_id),
}
response = self.client.post(path=url, data=data, format="json",)
......@@ -163,8 +163,7 @@ class MonitoringCaseViewTest(APITestCase):
url = self.BASE_URL + str(self.case_1.revision_id) + "/"
data = {
"positive_case_id": str(self.positive_case.revision_id),
"outcome": "Worsened",
"investigation_case_id": str(self.positive_investigation_case.revision_id),
"author": str(self.case_1.author.id),
}
prev_all_monitoring_case_revision_count = MonitoringCase.objects.all().count()
......@@ -174,7 +173,6 @@ class MonitoringCaseViewTest(APITestCase):
response = self.client.put(path=url, data=data, format="json",)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["outcome"], "Worsened")
current_monitoring_case_revision_count = MonitoringCase.objects.all().count()
current_active_monitoring_case_revision_count = (
......@@ -207,27 +205,12 @@ class MonitoringCaseViewTest(APITestCase):
url = self.BASE_URL + str(self.inactive_case.revision_id) + "/"
data = {
"positive_case_id": str(self.positive_case.revision_id),
"outcome": "Worsened",
"investigation_case_id": str(self.positive_investigation_case.revision_id),
"author": str(self.case_1.author.id),
}
response = self.client.put(path=url, data=data, format="json",)
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
def test_monitoring_case_cannot_have_more_than_one_reference(self):
url = self.BASE_URL
data = {
"positive_case_id": str(self.positive_case.revision_id),
"investigation_case_id": str(self.investigation_case.revision_id),
"outcome": "Healed",
"author": str(self.case_1.author.id),
}
with self.assertRaises(ValidationError):
self.client.post(
path=url, data=data, format="json",
)
def test_soft_delete_monitoring_case_success(self):
url = self.BASE_URL + str(self.case_1.revision_id) + "/"
response = self.client.delete(path=url, format="json",)
......
import json
import pytz
from datetime import datetime
from rest_framework import status
from rest_framework.authtoken.models import Token
from rest_framework.test import APITestCase, APIClient
from apps.accounts.tests.factories.accounts import AccountFactory, UserFactory
from apps.cases.models import PositiveCase
from apps.cases.tests.factories.case_subjects import CaseSubjectFactory
from apps.cases.tests.factories.cases import PositiveCaseFactory
from apps.constants import (
HEADER_PREFIX,
TIMEZONE,
ACTIVITY_TYPE_CREATE,
ACTIVITY_TYPE_EDIT,
ACTIVITY_TYPE_DELETE,
)
class PositiveCaseViewTest(APITestCase):
@classmethod
def setUpTestData(self):
self.BASE_URL = "/cases/positive-cases/"
self.user_1 = UserFactory(username="user_1", password="justpass")
self.author = AccountFactory(user=self.user_1, admin=False)
self.token_1, _ = Token.objects.get_or_create(user=self.user_1)
self.case_subject = CaseSubjectFactory()
self.case = PositiveCaseFactory(
author=self.author, case_subject_id=self.case_subject.subject_id,
)
self.other_deleted_case = PositiveCaseFactory(
author=self.author,
case_subject_id=self.case_subject.subject_id,
deleted_at=datetime.now(tz=pytz.timezone(TIMEZONE)),
)
self.inactive_case = PositiveCaseFactory(
author=self.author,
case_subject_id=self.case_subject.subject_id,
is_active=False,
)
def setUp(self):
self.client = APIClient(HTTP_AUTHORIZATION=HEADER_PREFIX + self.token_1.key)
def test_string_representation(self):
inactive_case_str = (
f"[Inactive] Rev. {self.inactive_case.revision_id} | by {self.inactive_case.author}"
)