diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7c66932..39f9299 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,7 @@ jobs: fail-fast: false matrix: python-version: ['3.11'] - django-version: ['4.1', '4.2', 'dev'] + django-version: ['4.2', 'dev'] services: mysql: image: mysql:latest diff --git a/edc_microbiology/tests/models.py b/edc_microbiology/tests/models.py deleted file mode 100644 index 1c61ff8..0000000 --- a/edc_microbiology/tests/models.py +++ /dev/null @@ -1,31 +0,0 @@ -from django.db import models -from edc_appointment.model_mixins import AppointmentModelMixin -from edc_model.models import BaseUuidModel -from edc_sites.models import SiteModelMixin -from edc_visit_tracking.model_mixins import VisitModelMixin - - -class Appointment(AppointmentModelMixin, SiteModelMixin, BaseUuidModel): - def raise_if_offstudy(self, **kwargs): - pass - - def timepoint_open_or_raise(self): - pass - - def update_timepoint(self): - pass - - class Meta(BaseUuidModel.Meta): - pass - - -class SubjectVisit(VisitModelMixin, BaseUuidModel): - appointment = models.OneToOneField( - Appointment, on_delete=models.PROTECT, related_name="subjectvisittest" - ) - - def raise_if_offstudy(self): - pass - - class Meta(VisitModelMixin.Meta, BaseUuidModel.Meta): - pass diff --git a/edc_microbiology/tests/tests/test_form.py b/edc_microbiology/tests/tests/test_form.py index e8228b2..bc2194d 100644 --- a/edc_microbiology/tests/tests/test_form.py +++ b/edc_microbiology/tests/tests/test_form.py @@ -1,14 +1,16 @@ -from decimal import Decimal - from django import forms from django.core.exceptions import ValidationError from django.test import TestCase +from edc_appointment.models import Appointment +from edc_appointment.tests.helper import Helper from edc_constants.constants import NO, NOT_APPLICABLE, OTHER, POS, YES from edc_crf.crf_form_validator_mixins import BaseFormValidatorMixin from edc_form_validators import FormValidator -from edc_registration.models import RegisteredSubject +from edc_reference import site_reference_configs from edc_utils import get_utcnow -from edc_visit_schedule.constants import DAY1 +from edc_visit_schedule.site_visit_schedules import site_visit_schedules +from edc_visit_tracking.constants import SCHEDULED +from edc_visit_tracking.models import SubjectVisit from edc_microbiology.constants import ( BACTERIA, @@ -17,8 +19,7 @@ NO_GROWTH, ) from edc_microbiology.form_validators import MicrobiologyFormValidatorMixin - -from ..models import Appointment, SubjectVisit +from microbiology_app.visit_schedule import visit_schedule class MicrobiologyFormValidator( @@ -32,22 +33,31 @@ class MicrobiologyFormValidator( class TestMicrobiologyFormValidator(TestCase): + helper_cls = Helper + def setUp(self): - self.subject_identifier = "1234" - RegisteredSubject.objects.create( - subject_identifier=self.subject_identifier, - randomization_datetime=get_utcnow(), + self.subject_identifier = "1235" + self.helper = self.helper_cls(subject_identifier=self.subject_identifier) + self.visit_schedule_name = "visit_schedule" + self.schedule_name = "schedule" + + site_visit_schedules._registry = {} + site_visit_schedules.loaded = False + site_visit_schedules.register(visit_schedule) + + site_reference_configs.registry = {} + site_reference_configs.register_from_visit_schedule( + visit_models={"edc_appointment.appointment": "edc_visit_tracking.subjectvisit"} ) - appointment = Appointment.objects.create( - subject_identifier=self.subject_identifier, - appt_datetime=get_utcnow(), - visit_code=DAY1, - visit_schedule_name="visit_schedule", - schedule_name="schedule", - timepoint=Decimal("0.0"), + + self.helper.consent_and_put_on_schedule( + visit_schedule_name="visit_schedule", schedule_name="schedule" ) + appointment = Appointment.objects.all().order_by("timepoint_datetime")[0] self.subject_visit = SubjectVisit.objects.create( - appointment=appointment, subject_identifier=self.subject_identifier + appointment=appointment, + subject_identifier=self.subject_identifier, + reason=SCHEDULED, ) def test_urine_culture_performed_yes_require_urine_culture_result(self): diff --git a/microbiology_app/__init__.py b/microbiology_app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/microbiology_app/apps.py b/microbiology_app/apps.py new file mode 100644 index 0000000..b177ede --- /dev/null +++ b/microbiology_app/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig as DjangoAppConfig + + +class AppConfig(DjangoAppConfig): + name = "microbiology_app" diff --git a/microbiology_app/models.py b/microbiology_app/models.py new file mode 100644 index 0000000..6b02095 --- /dev/null +++ b/microbiology_app/models.py @@ -0,0 +1,61 @@ +from datetime import date + +from django.db import models +from django.db.models import PROTECT +from edc_crf.model_mixins import CrfModelMixin +from edc_identifier.managers import SubjectIdentifierManager +from edc_identifier.model_mixins import NonUniqueSubjectIdentifierFieldMixin +from edc_model.models import BaseUuidModel +from edc_registration.model_mixins import UpdatesOrCreatesRegistrationModelMixin +from edc_screening.model_mixins import ScreeningModelMixin +from edc_sites.models import SiteModelMixin +from edc_utils import get_utcnow +from edc_visit_schedule.model_mixins import OffScheduleModelMixin, OnScheduleModelMixin +from edc_visit_tracking.models import SubjectVisit + + +class SubjectScreening(ScreeningModelMixin, BaseUuidModel): + objects = SubjectIdentifierManager() + + +class SubjectConsent( + SiteModelMixin, + NonUniqueSubjectIdentifierFieldMixin, + UpdatesOrCreatesRegistrationModelMixin, + BaseUuidModel, +): + report_datetime = models.DateTimeField(default=get_utcnow) + + consent_datetime = models.DateTimeField(default=get_utcnow) + + version = models.CharField(max_length=25, default="1") + + identity = models.CharField(max_length=25) + + confirm_identity = models.CharField(max_length=25) + + dob = models.DateField(default=date(1995, 1, 1)) + + +class OnSchedule(SiteModelMixin, OnScheduleModelMixin, BaseUuidModel): + pass + + +class OffSchedule(SiteModelMixin, OffScheduleModelMixin, BaseUuidModel): + pass + + +class CrfOne(CrfModelMixin, BaseUuidModel): + subject_visit = models.ForeignKey(SubjectVisit, on_delete=PROTECT) + + report_datetime = models.DateTimeField(default=get_utcnow) + + f1 = models.CharField(max_length=50, null=True, blank=True) + + f2 = models.CharField(max_length=50, null=True, blank=True) + + f3 = models.CharField(max_length=50, null=True, blank=True) + + next_appt_date = models.DateField(null=True, blank=True) + + next_visit_code = models.CharField(max_length=50, null=True, blank=True) diff --git a/microbiology_app/urls.py b/microbiology_app/urls.py new file mode 100644 index 0000000..d93e673 --- /dev/null +++ b/microbiology_app/urls.py @@ -0,0 +1,15 @@ +from django.contrib import admin +from django.urls import include, path +from django.views.generic import RedirectView + +app_name = "microbiology_app" + + +urlpatterns = [] + + +urlpatterns += [ + path("admin/", admin.site.urls), + path("i18n/", include("django.conf.urls.i18n")), + path("", RedirectView.as_view(url="admin/"), name="logout"), +] diff --git a/microbiology_app/visit_schedule.py b/microbiology_app/visit_schedule.py new file mode 100644 index 0000000..d97a5d0 --- /dev/null +++ b/microbiology_app/visit_schedule.py @@ -0,0 +1,67 @@ +from dateutil.relativedelta import relativedelta +from edc_visit_schedule.schedule import Schedule +from edc_visit_schedule.visit import Crf, FormsCollection, Visit +from edc_visit_schedule.visit_schedule import VisitSchedule + +crfs = FormsCollection(Crf(show_order=1, model="microbiology_app.crfone", required=True)) + +visit0 = Visit( + code="1000", + title="Day 1", + timepoint=0, + rbase=relativedelta(days=0), + rlower=relativedelta(days=0), + rupper=relativedelta(days=6), + crfs=crfs, +) + +visit1 = Visit( + code="2000", + title="Day 2", + timepoint=1, + rbase=relativedelta(days=1), + rlower=relativedelta(days=0), + rupper=relativedelta(days=6), + crfs=crfs, +) + +visit2 = Visit( + code="3000", + title="Day 3", + timepoint=2, + rbase=relativedelta(days=2), + rlower=relativedelta(days=0), + rupper=relativedelta(days=6), + crfs=crfs, +) + +visit3 = Visit( + code="4000", + title="Day 4", + timepoint=3, + rbase=relativedelta(days=3), + rlower=relativedelta(days=0), + rupper=relativedelta(days=6), + crfs=crfs, +) + +schedule = Schedule( + name="schedule", + onschedule_model="microbiology_app.onschedule", + offschedule_model="microbiology_app.offschedule", + appointment_model="edc_appointment.appointment", + consent_model="microbiology_app.subjectconsent", +) + +schedule.add_visit(visit0) +schedule.add_visit(visit1) +schedule.add_visit(visit2) +schedule.add_visit(visit3) + +visit_schedule = VisitSchedule( + name="visit_schedule", + offstudy_model="edc_offstudy.subjectoffstudy", + death_report_model="edc_adverse_event.deathreport", +) + +visit_schedule.add_schedule(schedule) diff --git a/pyproject.toml b/pyproject.toml index 58cbd98..001ad65 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,12 +6,12 @@ version_file="_version.py" [tool.black] line-length = 95 -target-version = ["py310"] +target-version = ["py311"] extend-exclude = '''^(.*\/)*\b(migrations)\b($|\/.*$)''' [tool.isort] profile = "black" -py_version = "310" +py_version = "311" skip = [".tox", ".eggs", "migrations"] [tool.coverage.run] diff --git a/runtests.py b/runtests.py index 8d089a3..9bf2f6b 100644 --- a/runtests.py +++ b/runtests.py @@ -7,6 +7,7 @@ import django from django.conf import settings from django.test.runner import DiscoverRunner +from edc_constants.constants import IGNORE from edc_test_utils import DefaultTestSettings app_name = "edc_microbiology" @@ -14,12 +15,18 @@ DEFAULT_SETTINGS = DefaultTestSettings( calling_file=__file__, - template_dirs=[os.path.join(base_dir, app_name, "tests", "templates")], BASE_DIR=base_dir, APP_NAME=app_name, - ETC_DIR=os.path.join(base_dir, app_name, "tests", "etc"), - SUBJECT_VISIT_MODEL="edc_microbiology.subjectvisit", - SUBJECT_VISIT_MISSED_MODEL="edc_appointment.subjectvisitmissed", + ETC_DIR=os.path.join(base_dir, "edc_microbiology", "tests", "etc"), + SUBJECT_VISIT_MODEL="edc_visit_tracking.subjectvisit", + SUBJECT_VISIT_MISSED_MODEL="edc_visit_tracking.subjectvisitmissed", + SUBJECT_SCREENING_MODEL="microbiology_app.subjectscreening", + SUBJECT_CONSENT_MODEL="microbiology_app.subjectconsent", + SUBJECT_REQUISITION_MODEL="microbiology_app.subjectrequisition", + SUBJECT_APP_LABEL="microbiology_app", + EDC_NAVBAR_DEFAULT=app_name, + EDC_NAVBAR_VERIFY_ON_LOAD=IGNORE, + EDC_AUTH_SKIP_SITE_AUTHS=True, INSTALLED_APPS=[ "django.contrib.admin", "django.contrib.auth", @@ -32,17 +39,27 @@ "multisite", "django_crypto_fields.apps.AppConfig", "edc_auth.apps.AppConfig", + "edc_action_item.apps.AppConfig", "edc_appointment.apps.AppConfig", "edc_notification.apps.AppConfig", "edc_export.apps.AppConfig", "edc_crf.apps.AppConfig", + "edc_device.apps.AppConfig", + "edc_identifier.apps.AppConfig", "edc_timepoint.apps.AppConfig", "edc_registration.apps.AppConfig", "edc_metadata.apps.AppConfig", + "edc_facility.apps.AppConfig", + "edc_offstudy.apps.AppConfig", + "edc_reference.apps.AppConfig", "edc_sites.apps.AppConfig", + "edc_visit_schedule.apps.AppConfig", + "edc_visit_tracking.apps.AppConfig", "edc_microbiology.apps.AppConfig", + "microbiology_app.apps.AppConfig", ], add_dashboard_middleware=True, + use_test_urls=False, ).settings diff --git a/setup.cfg b/setup.cfg index 77723be..8dc57db 100644 --- a/setup.cfg +++ b/setup.cfg @@ -12,7 +12,7 @@ keywords = django Edc microbiology, CRF, clinicedc, clinical trials classifiers= Environment :: Web Environment Framework :: Django - Framework :: Django :: 4.1 + Framework :: Django :: 4.2 Intended Audience :: Developers Intended Audience :: Science/Research Operating System :: OS Independent