-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'release/0.1.3' into main
- Loading branch information
Showing
14 changed files
with
384 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,46 +1,55 @@ | ||
from __future__ import annotations | ||
|
||
from typing import TYPE_CHECKING | ||
|
||
from edc_crf.crf_form_validator import CrfFormValidator | ||
from edc_dx_review.utils import raise_if_clinical_review_does_not_exist | ||
from edc_form_validators import INVALID_ERROR | ||
|
||
if TYPE_CHECKING: | ||
from edc_facility.models import HealthFacility | ||
|
||
|
||
class NextAppointmentFormValidatorMixin(CrfFormValidator): | ||
def __init__(self, **kwargs): | ||
self._clinic_days = None | ||
self._clinic_days_str = None | ||
self._health_facility = None | ||
super().__init__(**kwargs) | ||
|
||
def clean(self): | ||
raise_if_clinical_review_does_not_exist(self.cleaned_data.get("subject_visit")) | ||
super().clean() | ||
|
||
@property | ||
def clinic_days(self) -> list[int]: | ||
if not self._clinic_days: | ||
def health_facility(self) -> HealthFacility | None: | ||
if not self._health_facility: | ||
if self.cleaned_data.get("health_facility"): | ||
self._clinic_days = self.cleaned_data.get("health_facility").clinic_days | ||
return self._clinic_days | ||
self._health_facility = self.cleaned_data.get("health_facility") | ||
else: | ||
raise self.raise_validation_error( | ||
{"health_facility": "This field is required."} | ||
) | ||
return self._health_facility | ||
|
||
def validate_date_is_on_clinic_day(self): | ||
if appt_date := self.cleaned_data.get("appt_date"): | ||
if appt_date.isoweekday() > 5: | ||
day = "Sat" if appt_date.isoweekday() == 6 else "Sun" | ||
raise self.raise_validation_error( | ||
{"appt_date": f"Expected Mon-Fri. Got {day}"}, | ||
INVALID_ERROR, | ||
) | ||
if appt_date and self.cleaned_data.get("subject_visit").site: | ||
if ( | ||
self.integrated_clinic_days | ||
and appt_date.isoweekday() not in self.integrated_clinic_days | ||
): | ||
dct = dict(zip([1, 2, 3, 4, 5, 6, 7], ["M", "T", "W", "Th", "F", "Sa", "Su"])) | ||
expected_days = [v for k, v in dct.items() if k in self.clinic_days] | ||
raise self.raise_validation_error( | ||
{ | ||
"appt_date": ( | ||
"Invalid clinic day. " | ||
f"Expected {''.join(expected_days)}. " | ||
f"Got {appt_date.strftime('%A')}" | ||
) | ||
}, | ||
INVALID_ERROR, | ||
) | ||
if not self.health_facility.clinic_days: | ||
if appt_date.isoweekday() > 5: | ||
day = "Sat" if appt_date.isoweekday() == 6 else "Sun" | ||
raise self.raise_validation_error( | ||
{"appt_date": f"Expected Mon-Fri. Got {day}"}, | ||
INVALID_ERROR, | ||
) | ||
else: | ||
if appt_date.isoweekday() not in self.health_facility.clinic_days: | ||
raise self.raise_validation_error( | ||
{ | ||
"appt_date": ( | ||
"Invalid clinic day for facility. " | ||
f"Expected {self.health_facility.clinic_days_str}. " | ||
f"Got {appt_date.strftime('%A')}" | ||
) | ||
}, | ||
INVALID_ERROR, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
2019-01-01,New Year's Day,tanzania | ||
2019-01-12,Zanzibar Revolution Day,tanzania | ||
2019-04-07,The Sheikh Abeid Amani Karume Day,tanzania | ||
2019-04-17,Easter Monday,tanzania | ||
2019-04-26,Union Day,tanzania | ||
2019-05-01,Labour Day,tanzania | ||
2019-06-26,Eid al-Fitr,tanzania | ||
2019-07-07,Saba Saba Day,tanzania | ||
2019-07-14,Good Friday,tanzania | ||
2019-08-08,Nane Nane Day,tanzania | ||
2019-10-14,Nyerere Day,tanzania | ||
2019-12-01,Mawlid Day,tanzania | ||
2019-12-09,Independence Day,tanzania | ||
2019-12-25,Christmas Day,tanzania | ||
2019-12-26,Boxing Day,tanzania | ||
2019-01-01,New Year's Day,uganda | ||
2019-01-12,Zanzibar Revolution Day,uganda | ||
2019-04-07,The Sheikh Abeid Amani Karume Day,uganda | ||
2019-04-17,Easter Monday,uganda | ||
2019-04-26,Union Day,uganda | ||
2019-05-01,Labour Day,uganda | ||
2019-06-26,Eid al-Fitr,uganda | ||
2019-07-07,Saba Saba Day,uganda | ||
2019-07-14,Good Friday,uganda | ||
2019-08-08,Nane Nane Day,uganda | ||
2019-10-14,Nyerere Day,uganda | ||
2019-12-01,Mawlid Day,uganda | ||
2019-12-09,Independence Day,uganda | ||
2019-12-25,Christmas Day,uganda | ||
2019-12-26,Boxing Day,uganda |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
from dateutil.relativedelta import relativedelta | ||
from django.contrib.auth.models import User | ||
from django.test import TestCase | ||
from edc_appointment.models import Appointment | ||
from edc_facility import import_holidays | ||
from edc_reference import site_reference_configs | ||
from edc_utils import get_utcnow | ||
from edc_visit_schedule import site_visit_schedules | ||
from edc_visit_schedule.apps import populate_visit_schedule | ||
from edc_visit_tracking.utils import get_related_visit_model_cls | ||
|
||
from next_appointment_app.models import SubjectConsent | ||
from next_appointment_app.visit_schedules import visit_schedule | ||
|
||
|
||
class TestNextAppointment(TestCase): | ||
def setUp(self): | ||
import_holidays() | ||
self.user = User.objects.create_superuser("user_login", "u@example.com", "pass") | ||
|
||
site_visit_schedules._registry = {} | ||
site_visit_schedules.loaded = False | ||
site_visit_schedules.register(visit_schedule) | ||
|
||
populate_visit_schedule() | ||
|
||
site_reference_configs.register_from_visit_schedule( | ||
visit_models={"edc_appointment.appointment": "next_appointment_app.subjectvisit"} | ||
) | ||
self.subject_identifier = "101-40990029-4" | ||
identity = "123456789" | ||
subject_consent = SubjectConsent.objects.create( | ||
subject_identifier=self.subject_identifier, | ||
consent_datetime=get_utcnow() - relativedelta(days=10), | ||
identity=identity, | ||
confirm_identity=identity, | ||
dob=get_utcnow() - relativedelta(years=25), | ||
) | ||
|
||
# put subject on schedule | ||
_, schedule = site_visit_schedules.get_by_onschedule_model( | ||
"next_appointment_app.onschedule" | ||
) | ||
schedule.put_on_schedule( | ||
subject_identifier=subject_consent.subject_identifier, | ||
onschedule_datetime=subject_consent.consent_datetime, | ||
) | ||
|
||
def test_ok(self): | ||
self.assertEqual(5, Appointment.objects.all().count()) | ||
get_related_visit_model_cls() |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
from django.contrib import admin | ||
from edc_model_admin.dashboard import ( | ||
ModelAdminCrfDashboardMixin, | ||
ModelAdminSubjectDashboardMixin, | ||
) | ||
|
||
from .admin_site import next_appointment_app_admin | ||
from .models import CrfOne, OffSchedule, OnSchedule, SubjectConsent, SubjectVisit | ||
|
||
|
||
@admin.register(OnSchedule, site=next_appointment_app_admin) | ||
class OnScheduleAdmin(ModelAdminSubjectDashboardMixin, admin.ModelAdmin): | ||
pass | ||
|
||
|
||
@admin.register(OffSchedule, site=next_appointment_app_admin) | ||
class OffScheduleAdmin(ModelAdminSubjectDashboardMixin, admin.ModelAdmin): | ||
pass | ||
|
||
|
||
@admin.register(SubjectConsent, site=next_appointment_app_admin) | ||
class SubjectConsentAdmin(ModelAdminSubjectDashboardMixin, admin.ModelAdmin): | ||
pass | ||
|
||
|
||
@admin.register(SubjectVisit, site=next_appointment_app_admin) | ||
class SubjectVisitAdmin(ModelAdminSubjectDashboardMixin, admin.ModelAdmin): | ||
pass | ||
|
||
|
||
@admin.register(CrfOne, site=next_appointment_app_admin) | ||
class CrfOneAdmin(ModelAdminCrfDashboardMixin, admin.ModelAdmin): | ||
show_save_next = True | ||
show_cancel = True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
from edc_model_admin.admin_site import EdcAdminSite | ||
|
||
from .apps import AppConfig | ||
|
||
next_appointment_app_admin = EdcAdminSite( | ||
name="next_appointment_app_admin", app_label=AppConfig.name | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from django.apps import AppConfig as DjangoAppConfig | ||
|
||
|
||
class AppConfig(DjangoAppConfig): | ||
name = "next_appointment_app" | ||
verbose_name = "next_appointment_app" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
from edc_consent.consent import Consent | ||
from edc_consent.site_consents import site_consents | ||
from edc_constants.constants import FEMALE, MALE | ||
from edc_protocol import Protocol | ||
|
||
v1 = Consent( | ||
"next_appointment_app.subjectconsent", | ||
version="1", | ||
start=Protocol().study_open_datetime, | ||
end=Protocol().study_close_datetime, | ||
age_min=18, | ||
age_is_adult=18, | ||
age_max=110, | ||
gender=[MALE, FEMALE], | ||
) | ||
|
||
site_consents.register(v1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import uuid | ||
|
||
from django.db import models | ||
from edc_consent.field_mixins import PersonalFieldsMixin | ||
from edc_consent.field_mixins.identity_fields_mixin import IdentityFieldsMixin | ||
from edc_consent.model_mixins import ConsentModelMixin | ||
from edc_identifier.managers import SubjectIdentifierManager | ||
from edc_identifier.model_mixins import UniqueSubjectIdentifierFieldMixin | ||
from edc_metadata.model_mixins.updates import UpdatesCrfMetadataModelMixin | ||
from edc_model.models import BaseUuidModel | ||
from edc_model.models.historical_records import HistoricalRecords | ||
from edc_offstudy.model_mixins import OffstudyModelMixin | ||
from edc_reference.model_mixins import ReferenceModelMixin | ||
from edc_registration.model_mixins import UpdatesOrCreatesRegistrationModelMixin | ||
from edc_sites.models import SiteModelMixin | ||
from edc_visit_schedule.model_mixins import OffScheduleModelMixin, OnScheduleModelMixin | ||
from edc_visit_tracking.model_mixins import VisitTrackingCrfModelMixin | ||
from edc_visit_tracking.models import SubjectVisit | ||
|
||
|
||
class OnSchedule(SiteModelMixin, OnScheduleModelMixin, BaseUuidModel): | ||
pass | ||
|
||
|
||
class OffSchedule(SiteModelMixin, OffScheduleModelMixin, BaseUuidModel): | ||
pass | ||
|
||
|
||
class SubjectOffstudy(OffstudyModelMixin, BaseUuidModel): | ||
class Meta(OffstudyModelMixin.Meta): | ||
pass | ||
|
||
|
||
class SubjectConsent( | ||
ConsentModelMixin, | ||
PersonalFieldsMixin, | ||
IdentityFieldsMixin, | ||
UniqueSubjectIdentifierFieldMixin, | ||
UpdatesOrCreatesRegistrationModelMixin, | ||
SiteModelMixin, | ||
BaseUuidModel, | ||
): | ||
objects = SubjectIdentifierManager() | ||
|
||
history = HistoricalRecords() | ||
|
||
def natural_key(self): | ||
return (self.subject_identifier,) # noqa | ||
|
||
|
||
class BaseCrfModel( | ||
VisitTrackingCrfModelMixin, | ||
SiteModelMixin, | ||
UpdatesCrfMetadataModelMixin, | ||
ReferenceModelMixin, | ||
models.Model, | ||
): | ||
subject_visit = models.OneToOneField( | ||
SubjectVisit, on_delete=models.PROTECT, related_name="next_appointment_subjectvisit" | ||
) | ||
|
||
f1 = models.CharField(max_length=50, default=uuid.uuid4) | ||
|
||
class Meta: | ||
abstract = True | ||
|
||
|
||
class CrfOne(BaseCrfModel, BaseUuidModel): | ||
f1 = models.CharField(max_length=50, null=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
from edc_navbar.navbar import Navbar | ||
from edc_navbar.site_navbars import site_navbars | ||
from edc_review_dashboard.navbars import navbar as review_navbar | ||
|
||
navbar = Navbar(name="next_appointment_app") | ||
|
||
for item in review_navbar.items: | ||
navbar.append_item(item) | ||
|
||
|
||
site_navbars.register(navbar) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
from django.contrib import admin | ||
from django.urls import path | ||
from django.views.generic import RedirectView | ||
from edc_utils.paths_for_urlpatterns import paths_for_urlpatterns | ||
|
||
from .admin_site import next_appointment_app_admin | ||
from .views import SubjectDashboardView | ||
|
||
app_name = "next_appointment_app" | ||
|
||
urlpatterns = SubjectDashboardView.urls(app_name, label="subject_dashboard") | ||
|
||
urlpatterns += [ | ||
*paths_for_urlpatterns("edc_next_appointment"), | ||
path("data_manager_app/admin/", next_appointment_app_admin.urls), | ||
path("/admin", admin.site.urls), | ||
path("", RedirectView.as_view("/admin"), name="home_url"), | ||
path("", RedirectView.as_view("/admin"), name="administration_url"), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from edc_subject_dashboard.views import SubjectDashboardView as BaseSubjectDashboardView | ||
|
||
|
||
class SubjectDashboardView(BaseSubjectDashboardView): | ||
consent_model = "next_appointment_app.subjectconsent" | ||
navbar_name = "next_appointment_app" | ||
visit_model = "next_appointment_app.subjectvisit" | ||
|
||
def get_navbar_context_data(self, context): | ||
return context |
Oops, something went wrong.