|pypi| |actions| |codecov| |downloads|

edc-appointment
---------------

This module works closely with ``edc_visit_tracking`` and ``edc_visit_schedule``.

Subject data is collected on predefined timepoints. We describe these data collection timepoints in a ``visit_schedule`` as provided by ``edc-visit-schedule``. In ``edc-appointment`` timepoints are represented by appointments. ``edc-appointment`` provides classes for creating and managing appointments.

See also ``edc-visit-schedule``.


AppointmentModelMixin
+++++++++++++++++++++

A model mixin for the Appointment model. Each project may have one appointment model. For example:

.. code-block:: python

    class Appointment(AppointmentModelMixin, RequiresConsentModelMixin, BaseUuidModel):

        class Meta(AppointmentModelMixin.Meta):
            consent_model = 'edc_example.subjectconsent'
            app_label = 'edc_example'


Appointment is a required foreignkey for the visit report
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++

The ``Appointment`` model is a required foreignkey for the visit report. Be sure to set ``on_delete=PROTECT``.

.. code-block:: python

    class SubjectVisit(VisitModelMixin, OffstudyMixin, CreatesMetadataModelMixin,
                       RequiresConsentModelMixin, BaseUuidModel):

        appointment = models.OneToOneField(Appointment, on_delete=PROTECT)

        objects = VisitModelManager()

        class Meta(VisitModelMixin.Meta):
            consent_model = 'edc_example.subjectconsent'
            app_label = 'edc_example'


CreatesAppointmentsModelMixin
+++++++++++++++++++++++++++++

A model mixin for the model that triggers the creation of appointments when the model is saved. This is typically an enrollment model.

Adds the model field ``facility``. The value of field ``facility`` tells the ``CreateAppointmentsMixin`` to create appointments for the subject on dates that are available at the ``facility``.

.. code-block:: python

    class Enrollment(EnrollmentModelMixin, CreateAppointmentsMixin,
                     RequiresConsentModelMixin, BaseUuidModel):

        class Meta(EnrollmentModelMixin.Meta):
            visit_schedule_name = 'subject_visit_schedule.schedule1'
            consent_model = 'edc_example.subjectconsent'
            app_label = 'edc_example'

When ``Enrollment`` declared above is saved, one appointment will be created for the subject for each ``visit`` in schedule ``schedule1`` of visit_schedule ``subject_visit_schedule``.

Note: the value for ``facility`` must be provided by the user, either through the form interface or programmatically.


Customizing appointment scheduling by ``Facility``
++++++++++++++++++++++++++++++++++++++++++++++++++

see ``edc_facility``


Available Appointment Model Manager Methods
===========================================

The ``Appointment`` model is declared with ``AppointmentManager``. It has several useful methods.


first_appointment() last_appointment()
++++++++++++++++++++++++++++++++++++++

Returns the first (or last) appointment. If just the ``subject_identifier`` is provided, the first appointment of the protocol for the subject is returned. To be more specific, provide ``{subject_identifier=subject_identifier, visit_schedule_name=visit_schedule_name}``.
To be even more specific,  ``{subject_identifier=subject_identifier, visit_schedule_name=visit_schedule_name, schedule_name=schedule_name}``.

The most common usage is to just provide these values with an appointment instance:

.. code-block:: python

    first_appointment = Appointment.objects.first_appointment(appointment=appointment)


next_appointment() previous_appointment()
+++++++++++++++++++++++++++++++++++++++++

The next and previous appointment are relative to the schedule and a visit_code within that schedule. If next is called on the last appointment in the sequence ``None`` is returned. If previous is called on the first appointment in the sequence ``None`` is returned.

For example, in a sequence of appointment 1000, 2000, 3000, 4000:

.. code-block:: python

    >>> appointment.visit_code
    1000
    >>> next_appointment = Appointment.objects.next_appointment(appointment=appointment)
    >>> next_appointment.visit_code
    2000


But you can also pass an appointment instance and pass the visit code:

.. code-block:: python

    >>> appointment.visit_code
    1000
    >>> next_appointment = Appointment.objects.next_appointment(
            appointment=appointment, visit_code=3000)
    >>> next_appointment.visit_code
    4000


If you ask for the next appointment from the last, ``None`` is returned:

.. code-block:: python

    >>> appointment.visit_code
    4000
    >>> next_appointment = Appointment.objects.next_appointment(
            appointment=appointment, visit_code=3000)
    >>> next_appointment.visit_code
    AttributeError: 'NoneType' object has no attribute 'visit_code'


The ``previous_appointment`` acts as expected:

.. code-block:: python

    >>> appointment.visit_code
    1000
    >>> previous_appointment = Appointment.objects.previous_appointment(appointment=appointment)
    >>> previous_appointment.visit_code
    AttributeError: 'NoneType' object has no attribute 'visit_code'


delete_for_subject_after_date()
+++++++++++++++++++++++++++++++

This method will delete all appointments for a subject after a given datetime. See also ``edc-offstudy``.

``Appointment`` is usually a foreignkey of a visit model. It's important when using this method to ensure that when declaring ``Appointment`` as a foreignkey you explicitly set ``on_delete=PROTECT``. If you don't, the deletion will cascade to other related instances -- and that's bad.

.. code-block:: python

    appointment = models.OneToOneField(Appointment, on_delete=PROTECT)


.. |pypi| image:: https://img.shields.io/pypi/v/edc-appointment.svg
   :target: https://pypi.python.org/pypi/edc-appointment

.. |actions| image:: https://github.com/clinicedc/edc-appointment/workflows/build/badge.svg?branch=develop
  :target: https://github.com/clinicedc/edc-appointment/actions?query=workflow:build

.. |codecov| image:: https://codecov.io/gh/clinicedc/edc-appointment/branch/develop/graph/badge.svg
   :target: https://codecov.io/gh/clinicedc/edc-appointment

.. |downloads| image:: https://pepy.tech/badge/edc-appointment
   :target: https://pepy.tech/project/edc-appointment
