clinicedc 2.0.6__py3-none-any.whl → 2.0.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of clinicedc might be problematic. Click here for more details.
- {clinicedc-2.0.6.dist-info → clinicedc-2.0.7.dist-info}/METADATA +2 -2
- {clinicedc-2.0.6.dist-info → clinicedc-2.0.7.dist-info}/RECORD +386 -335
- edc_action_item/action.py +1 -1
- edc_action_item/action_item_notification.py +2 -2
- edc_action_item/create_action_item.py +1 -1
- edc_action_item/decorators.py +1 -1
- edc_action_item/migrations/0001_initial.py +21 -22
- edc_action_item/migrations/0006_auto_20180707_1659.py +4 -4
- edc_action_item/migrations/0008_auto_20180809_0303.py +4 -4
- edc_action_item/migrations/0015_auto_20190114_0250.py +4 -4
- edc_action_item/migrations/0017_auto_20190305_0123.py +11 -30
- edc_action_item/migrations/0030_edcpermissions.py +3 -2
- edc_action_item/migrations/0039_alter_actionitem_auto_created_comment_and_more.py +398 -0
- edc_action_item/migrations/0040_alter_actionitem_report_datetime_and_more.py +34 -0
- edc_action_item/models/action_item.py +9 -4
- edc_action_item/models/action_model_mixin.py +4 -4
- edc_action_item/models/reference.py +2 -2
- edc_action_item/post_migrate_signals.py +1 -1
- edc_action_item/send_email.py +0 -85
- edc_adherence/migrations/0005_alter_nonadherencereasons_extra_value_and_more.py +36 -0
- edc_adherence/model_mixins.py +1 -1
- edc_adverse_event/migrations/0001_initial.py +5 -4
- edc_adverse_event/migrations/0002_auto_20190802_0059.py +3 -2
- edc_adverse_event/migrations/0008_auto_20220825_0451.py +3 -2
- edc_adverse_event/migrations/0009_auto_20220907_0157.py +3 -2
- edc_adverse_event/migrations/0016_alter_aeactionclassification_device_created_and_more.py +285 -0
- edc_adverse_event/model_mixins/ae_followup/ae_followup_fields_model_mixin.py +2 -2
- edc_adverse_event/model_mixins/ae_initial/ae_initial_fields_model_mixin.py +6 -5
- edc_adverse_event/model_mixins/ae_special_interest/aesi_fields_model_mixin.py +2 -2
- edc_adverse_event/model_mixins/ae_susar/ae_susar_fields_model_mixin.py +2 -2
- edc_adverse_event/model_mixins/ae_tmg/ae_tmg_fields_model_mixin.py +15 -11
- edc_adverse_event/model_mixins/death_report/death_report_model_mixin.py +5 -4
- edc_adverse_event/model_mixins/death_report/death_report_tmg_model_mixin.py +6 -3
- edc_adverse_event/model_mixins/death_report/simple_death_report_model_mixin.py +2 -2
- edc_adverse_event/model_mixins/hospitaization/hospitalization_model_mixin.py +4 -3
- edc_adverse_event/modeladmin_mixins/death_report_admin_mixin.py +3 -3
- edc_adverse_event/models/signals.py +7 -7
- edc_adverse_event/templatetags/edc_adverse_event_extras.py +5 -4
- edc_adverse_event/view_mixins/ae/ae_listboard_view_mixin.py +3 -5
- edc_adverse_event/view_mixins/ae/death_report_listboard_view_mixin.py +6 -8
- edc_adverse_event/view_mixins/tmg/tmg_ae_listboard_view_mixin.py +2 -2
- edc_adverse_event/views/tmg/summary_listboard_view.py +3 -2
- edc_appointment/admin/appointment_admin.py +2 -2
- edc_appointment/admin/list_filters.py +2 -2
- edc_appointment/form_validators/appointment_form_validator.py +108 -82
- edc_appointment/migrations/0003_auto_20161127_2226.py +5 -6
- edc_appointment/migrations/0006_auto_20170106_2118.py +5 -5
- edc_appointment/migrations/0018_auto_20190305_0123.py +5 -12
- edc_appointment/migrations/0050_alter_appointment_appt_type_and_more.py +220 -0
- edc_appointment/model_mixins/appointment_fields_model_mixin.py +1 -2
- edc_appointment/model_mixins/window_period_model_mixin.py +6 -7
- edc_appointment/models/signals.py +44 -35
- edc_appointment/view_utils/appointment_button.py +2 -2
- edc_auth/admin/user_admin.py +1 -1
- edc_auth/migrations/0001_squashed_0033_alter_userprofile_is_multisite_viewer.py +5 -5
- edc_auth/migrations/0012_auto_20191026_0034.py +3 -2
- edc_auth/migrations/0013_auto_20191026_0055.py +3 -2
- edc_auth/migrations/0025_permissions.py +3 -2
- edc_auth/migrations/0035_alter_edcpermissions_device_created_and_more.py +85 -0
- edc_auth/post_migrate_signals.py +1 -1
- edc_consent/actions.py +4 -5
- edc_consent/migrations/0001_initial.py +3 -2
- edc_consent/migrations/0006_alter_edcpermissions_device_created_and_more.py +49 -0
- edc_consent/model_mixins/consent_extension_model_mixin.py +4 -5
- edc_consent/model_mixins/requires_consent_fields_model_mixin.py +2 -2
- edc_consent/utils.py +1 -1
- edc_crf/migrations/0001_initial.py +3 -2
- edc_crf/migrations/0009_alter_crfstatus_device_created_and_more.py +54 -0
- edc_dashboard/migrations/0001_initial.py +3 -2
- edc_dashboard/migrations/0006_alter_edcpermissions_device_created_and_more.py +49 -0
- edc_dashboard/templatetags/edc_dashboard_extras.py +3 -2
- edc_data_manager/action_items.py +4 -6
- edc_data_manager/admin/actions.py +5 -5
- edc_data_manager/handlers/handlers.py +6 -7
- edc_data_manager/migrations/0001_initial.py +19 -19
- edc_data_manager/migrations/0025_edcpermissions.py +3 -2
- edc_data_manager/migrations/0040_alter_datadictionary_device_created_and_more.py +327 -0
- edc_data_manager/migrations/0041_alter_dataquery_dm_user_and_more.py +164 -0
- edc_data_manager/models/data_query.py +5 -5
- edc_data_manager/models/model_mixins.py +8 -8
- edc_data_manager/rule/rule_runner.py +4 -3
- edc_document_status/model_mixins.py +1 -1
- edc_egfr/egfr.py +11 -7
- edc_egfr/model_mixins/egfr_model_mixin.py +3 -7
- edc_export/admin/data_request_admin.py +2 -2
- edc_export/archive_exporter.py +4 -3
- edc_export/files_archiver.py +3 -2
- edc_export/migrations/0001_initial.py +26 -26
- edc_export/migrations/0004_auto_20190305_0123.py +25 -72
- edc_export/migrations/0013_edcpermissions.py +3 -2
- edc_export/migrations/0022_alter_datarequest_description_and_more.py +611 -0
- edc_export/migrations/0023_alter_datarequesthistory_archive_filename_and_more.py +29 -0
- edc_export/model_exporter/file_history_updater.py +10 -10
- edc_export/model_exporter/model_exporter.py +13 -14
- edc_export/model_exporter/object_history_helpers.py +2 -2
- edc_export/models/data_request_history.py +4 -4
- edc_export/utils.py +10 -15
- edc_facility/facility.py +10 -15
- edc_facility/import_holidays.py +13 -13
- edc_facility/migrations/0005_healthfacility_healthfacilitytypes_and_more.py +8 -7
- edc_facility/migrations/0016_alter_healthfacility_device_created_and_more.py +139 -0
- edc_facility/migrations/0017_alter_healthfacility_gps_and_more.py +54 -0
- edc_facility/model_mixins.py +5 -5
- edc_form_runners/form_runner.py +3 -5
- edc_form_runners/migrations/0001_initial.py +3 -2
- edc_form_runners/migrations/0005_alter_issue_device_created_and_more.py +49 -0
- edc_identifier/migrations/0001_squashed_0018_auto_20180128_1054.py +3 -3
- edc_identifier/migrations/0002_auto_20190305_0123.py +3 -6
- edc_identifier/migrations/0006_auto_20161127_2226.py +15 -15
- edc_identifier/migrations/0007_auto_20161204_2227.py +3 -3
- edc_identifier/migrations/0009_auto_20161221_2323.py +3 -5
- edc_identifier/migrations/0010_auto_20170112_0602.py +17 -17
- edc_identifier/migrations/0011_alter_identifiermodel_device_created_and_more.py +79 -0
- edc_identifier/model_mixins.py +1 -1
- edc_identifier/models.py +9 -9
- edc_identifier/simple_identifier.py +1 -3
- edc_identifier/subject_identifier.py +3 -2
- edc_lab/migrations/0001_initial.py +29 -29
- edc_lab/migrations/0008_auto_20170921_0719.py +3 -3
- edc_lab/migrations/0010_auto_20171127_1541.py +15 -15
- edc_lab/migrations/0012_auto_20180114_1438.py +3 -3
- edc_lab/migrations/0019_auto_20190305_0123.py +43 -127
- edc_lab/migrations/0036_alter_aliquot_comment_alter_aliquot_device_created_and_more.py +1139 -0
- edc_lab/migrations/0037_alter_historicalorder_order_datetime_and_more.py +31 -0
- edc_lab/model_mixins/aliquot/aliquot_identifier_model_mixin.py +2 -2
- edc_lab/model_mixins/aliquot/aliquot_model_mixin.py +2 -2
- edc_lab/model_mixins/panel_model_mixin.py +18 -7
- edc_lab/model_mixins/requisition/crf_with_requisition_model_mixin.py +2 -4
- edc_lab/model_mixins/requisition/requisition_model_mixin.py +7 -8
- edc_lab/model_mixins/requisition/requisition_verify_model_mixin.py +1 -1
- edc_lab/model_mixins/result/result_item_model_mixin.py +4 -4
- edc_lab/model_mixins/shipping/manifest_model_mixin.py +4 -5
- edc_lab/model_mixins/shipping/verify_model_mixin.py +4 -6
- edc_lab/models/box.py +1 -1
- edc_lab/models/box_item.py +6 -7
- edc_lab/models/manifest/manifest.py +1 -1
- edc_lab/models/manifest/manifest_item.py +6 -6
- edc_lab/models/manifest/shipper.py +3 -4
- edc_lab/models/order.py +6 -4
- edc_lab/models/panel.py +4 -4
- edc_lab/models/result.py +2 -2
- edc_lab/models/result_item.py +2 -2
- edc_lab_dashboard/migrations/0001_initial.py +3 -2
- edc_lab_dashboard/migrations/0005_alter_edcpermissions_device_created_and_more.py +49 -0
- edc_lab_dashboard/views/action_views/receive_view.py +2 -2
- edc_lab_dashboard/views/action_views/verify_box_item_view.py +2 -2
- edc_lab_results/model_mixins/blood_result_model_mixin.py +7 -7
- edc_lab_results/model_mixins/fbg_model_mixin.py +3 -3
- edc_lab_results/model_mixins/glucose_model_mixin.py +3 -3
- edc_lab_results/model_mixins/hba1c_model_mixin.py +3 -3
- edc_label/migrations/0001_initial.py +3 -2
- edc_label/migrations/0007_alter_zpllabeltemplates_device_created_and_more.py +49 -0
- edc_list_data/list_model_maker.py +2 -2
- edc_list_data/load_list_data.py +11 -14
- edc_list_data/model_mixins.py +12 -4
- edc_list_data/preload_data.py +3 -3
- edc_listboard/migrations/0001_initial.py +3 -2
- edc_listboard/migrations/0007_alter_listboard_device_created_and_more.py +49 -0
- edc_locator/migrations/0001_initial.py +7 -7
- edc_locator/migrations/0018_auto_20190305_0123.py +5 -12
- edc_locator/migrations/0040_alter_historicalsubjectlocator_action_identifier_and_more.py +187 -0
- edc_locator/migrations/0041_alter_historicalsubjectlocator_report_datetime_and_more.py +27 -0
- edc_locator/model_mixins/locator_model_mixin.py +2 -2
- edc_locator/model_mixins/subject_contact_fields_mixin.py +1 -1
- edc_locator/modeladmin_mixins.py +5 -4
- edc_ltfu/model_mixins.py +7 -5
- edc_metadata/metadata_rules/decorators.py +1 -1
- edc_metadata/migrations/0002_auto_20161127_2226.py +5 -5
- edc_metadata/migrations/0005_auto_20170112_0602.py +5 -5
- edc_metadata/migrations/0011_auto_20190305_0123.py +5 -12
- edc_metadata/migrations/0031_alter_crfmetadata_device_created_and_more.py +120 -0
- edc_metadata/model_mixins/updates/updates_crf_metadata_model_mixin.py +1 -1
- edc_metadata/model_mixins/updates/updates_requisition_metadata_model_mixin.py +1 -1
- edc_metadata/models/crf_metadata.py +5 -5
- edc_metadata/models/crf_metadata_model_mixin.py +4 -5
- edc_metadata/models/requisition_metadata.py +6 -6
- edc_metadata/views/refresh_metadata_actions_view.py +3 -3
- edc_model/models/address_mixin.py +6 -6
- edc_model/models/fields/initials_field.py +2 -1
- edc_model/models/historical_records.py +2 -9
- edc_model/models/url_model_mixin.py +2 -2
- edc_model/validators/date.py +7 -8
- edc_model_admin/list_filters/future_date_list_filter.py +3 -3
- edc_model_admin/list_filters/past_date_list_filter.py +3 -3
- edc_model_admin/mixins/model_admin_protect_pii_mixin.py +4 -5
- edc_model_fields/fields/other_charfield.py +2 -2
- edc_navbar/migrations/0004_auto_20220825_0451.py +3 -2
- edc_navbar/migrations/0009_alter_edcpermissions_device_created_and_more.py +49 -0
- edc_notification/migrations/0001_initial.py +3 -3
- edc_notification/migrations/0004_auto_20190305_0123.py +3 -6
- edc_notification/migrations/0011_alter_notification_device_created_and_more.py +59 -0
- edc_notification/models/notification.py +1 -1
- edc_notification/notification/notification.py +12 -12
- edc_offstudy/migrations/0001_initial.py +4 -4
- edc_offstudy/migrations/0002_auto_20180921_0434.py +4 -4
- edc_offstudy/migrations/0005_auto_20190305_0123.py +5 -12
- edc_offstudy/migrations/0023_alter_historicalsubjectoffstudy_action_identifier_and_more.py +188 -0
- edc_offstudy/migrations/0024_alter_historicalsubjectoffstudy_offstudy_datetime_and_more.py +43 -0
- edc_offstudy/model_mixins/offstudy_model_mixin.py +3 -2
- edc_pdutils/df_exporters/csv_exporter.py +33 -37
- edc_pdutils/df_exporters/csv_model_exporter.py +2 -1
- edc_pdutils/migrations/0001_initial.py +8 -8
- edc_pharmacy/admin/prescription/rx_refill_admin.py +4 -3
- edc_pharmacy/admin/reports/stock_availability_admin.py +5 -6
- edc_pharmacy/migrations/0001_initial.py +64 -63
- edc_pharmacy/migrations/0015_auto_20220913_2139.py +26 -26
- edc_pharmacy/migrations/0024_allocation_assignment_containerunits_dispense_and_more.py +81 -86
- edc_pharmacy/migrations/0037_remove_historicalstock_confirmed_at_site_by_and_more.py +5 -5
- edc_pharmacy/migrations/0039_remove_dispense_registered_subject_and_more.py +7 -8
- edc_pharmacy/migrations/0049_remove_stocktransferconfirmation_stock_and_more.py +12 -12
- edc_pharmacy/migrations/0050_remove_stocktransferconfirmation2_location_and_more.py +5 -5
- edc_pharmacy/migrations/0051_alter_historicalstocktransferconfirmationitem_options_and_more.py +3 -4
- edc_pharmacy/migrations/0053_alter_location_managers_alter_historicalstock_lot_and_more.py +3 -3
- edc_pharmacy/migrations/0057_scanduplicates.py +3 -3
- edc_pharmacy/migrations/0060_alter_container_max_per_subject_and_more.py +13 -15
- edc_pharmacy/migrations/0068_stockout.py +2 -3
- edc_pharmacy/migrations/0076_historicalstockadjustment_stockadjustment.py +5 -5
- edc_pharmacy/migrations/0077_historicalstockadjustment_adjustment_datetime_and_more.py +3 -4
- edc_pharmacy/migrations/0081_historicalconfirmation_confirmation.py +8 -8
- edc_pharmacy/migrations/0084_confirmationatsiteitem_and_more.py +0 -2
- edc_pharmacy/migrations/0089_alter_allocation_allocated_by_and_more.py +3284 -0
- edc_pharmacy/migrations/0090_alter_allocation_allocation_datetime_and_more.py +227 -0
- edc_pharmacy/model_mixins/study_medication_refill_model_mixin.py +2 -2
- edc_pharmacy/models/medication/medication.py +3 -3
- edc_pharmacy/models/model_mixins.py +10 -11
- edc_pharmacy/models/prescription/rx.py +13 -12
- edc_pharmacy/models/prescription/rx_refill.py +0 -1
- edc_pharmacy/models/stock/allocation.py +3 -3
- edc_pharmacy/models/stock/confirmation.py +3 -3
- edc_pharmacy/models/stock/confirmation_at_site.py +3 -2
- edc_pharmacy/models/stock/confirmation_at_site_item.py +3 -4
- edc_pharmacy/models/stock/dispense.py +5 -6
- edc_pharmacy/models/stock/dispense_item.py +2 -2
- edc_pharmacy/models/stock/location.py +3 -4
- edc_pharmacy/models/stock/lot.py +6 -7
- edc_pharmacy/models/stock/order.py +1 -1
- edc_pharmacy/models/stock/receive.py +3 -3
- edc_pharmacy/models/stock/receive_item.py +4 -4
- edc_pharmacy/models/stock/repack_request.py +2 -2
- edc_pharmacy/models/stock/stock.py +12 -18
- edc_pharmacy/models/stock/stock_adjustment.py +4 -4
- edc_pharmacy/models/stock/stock_request.py +2 -2
- edc_pharmacy/models/stock/stock_request_item.py +2 -2
- edc_pharmacy/models/stock/stock_transfer.py +3 -3
- edc_pharmacy/models/stock/stock_transfer_item.py +2 -2
- edc_pharmacy/models/stock/storage_bin.py +3 -4
- edc_pharmacy/models/stock/storage_bin_item.py +2 -2
- edc_pharmacy/models/stock/supplier.py +3 -4
- edc_pharmacy/models/storage/box.py +2 -2
- edc_pharmacy/models/storage/items/container_model_mixin.py +3 -4
- edc_pharmacy/models/storage/items/pill_bottle_model_mixin.py +2 -2
- edc_pharmacy/models/storage/items/subject_pill_bottle.py +1 -1
- edc_pharmacy/models/storage/room.py +2 -2
- edc_pharmacy/models/storage/shelf.py +2 -2
- edc_pharmacy/models/storage/utils.py +1 -1
- edc_pharmacy/utils/allocate_stock.py +2 -3
- edc_pharmacy/utils/confirm_stock.py +2 -3
- edc_pharmacy/utils/confirm_stock_at_site.py +3 -4
- edc_pharmacy/utils/dispense.py +3 -4
- edc_pharmacy/utils/process_repack_request.py +4 -5
- edc_pharmacy/utils/stock_request/bulk_create_stock_request_items.py +2 -3
- edc_pharmacy/utils/transfer_stock.py +2 -3
- edc_pharmacy/views/add_to_storage_bin_view.py +2 -2
- edc_pharmacy/views/allocate_to_subject_view.py +2 -2
- edc_pharmacy/views/dispense_view.py +2 -2
- edc_pharmacy/views/move_to_storage_bin_view.py +2 -3
- edc_pharmacy/views/print_labels_view.py +2 -2
- edc_protocol/research_protocol_config.py +2 -3
- edc_protocol_incident/migrations/0001_initial.py +7 -7
- edc_protocol_incident/migrations/0001_squashed_0015_auto_20220927_0401.py +13 -13
- edc_protocol_incident/migrations/0005_protocolincident_historicalprotocolincident_and_more.py +7 -7
- edc_protocol_incident/migrations/0024_alter_actionsrequired_extra_value_and_more.py +625 -0
- edc_protocol_incident/migrations/0025_alter_historicalprotocoldeviationviolation_report_datetime_and_more.py +42 -0
- edc_protocol_incident/model_mixins/protocol_deviation_violation_model_mixin.py +18 -11
- edc_protocol_incident/model_mixins/protocol_incident_model_mixin.py +26 -11
- edc_pylabels/actions.py +3 -5
- edc_pylabels/migrations/0002_alter_label_options_label_created_and_more.py +3 -7
- edc_pylabels/migrations/0005_labelconfiguration_delete_label_and_more.py +3 -3
- edc_pylabels/migrations/0013_alter_labelconfiguration_device_created_and_more.py +49 -0
- edc_qareports/migrations/0001_initial.py +4 -5
- edc_qareports/migrations/0005_edcpermissions.py +3 -3
- edc_qareports/migrations/0006_qareportlog.py +2 -3
- edc_qareports/migrations/0019_alter_edcpermissions_device_created_and_more.py +102 -0
- edc_qareports/migrations/0020_alter_note_report_datetime_and_more.py +24 -0
- edc_qareports/model_mixins/note_model_mixin.py +7 -4
- edc_qareports/model_mixins/on_study_missing_values_model_mixin.py +4 -4
- edc_qareports/model_mixins/qa_report_model_mixin.py +2 -3
- edc_qareports/models/note.py +4 -4
- edc_qareports/models/qa_reports_log.py +2 -3
- edc_randomization/decorators.py +1 -1
- edc_randomization/migrations/0001_initial.py +3 -2
- edc_randomization/migrations/0002_historicalrandomizationlist.py +3 -2
- edc_randomization/migrations/0009_edcpermissions.py +3 -2
- edc_randomization/migrations/0014_alter_edcpermissions_device_created_and_more.py +141 -0
- edc_randomization/model_mixins.py +9 -9
- edc_randomization/utils.py +2 -2
- edc_refusal/migrations/0001_initial.py +4 -4
- edc_refusal/migrations/0002_historicalsubjectrefusal.py +4 -4
- edc_refusal/migrations/0012_alter_historicalsubjectrefusal_comment_and_more.py +122 -0
- edc_refusal/migrations/0013_alter_historicalsubjectrefusal_report_datetime_and_more.py +28 -0
- edc_refusal/model_mixins.py +3 -3
- edc_registration/migrations/0002_auto_20161127_2226.py +3 -4
- edc_registration/migrations/0005_auto_20170111_1809.py +4 -2
- edc_registration/migrations/0016_historicalregisteredsubject.py +3 -2
- edc_registration/migrations/0017_auto_20190305_0123.py +5 -12
- edc_registration/migrations/0033_alter_historicalregisteredsubject_additional_key_and_more.py +302 -0
- edc_registration/model_mixins/updates_or_creates_registered_subject_model_mixin.py +2 -3
- edc_registration/models/registered_subject.py +27 -26
- edc_reportable/age_evaluator.py +4 -2
- edc_reportable/formula.py +5 -5
- edc_reportable/migrations/0001_initial.py +7 -7
- edc_reportable/migrations/0003_referencerangecollection_grade1_and_more.py +3 -3
- edc_reportable/migrations/0004_alter_referencerangecollection_grade3_and_more.py +5 -5
- edc_reportable/migrations/0006_alter_gradingdata_revision_and_more.py +5 -6
- edc_reportable/migrations/0007_alter_gradingdata_age_phrase_and_more.py +509 -0
- edc_reportable/models/normal_data.py +4 -5
- edc_reportable/models/reference_model_mixins.py +10 -11
- edc_reportable/models/reference_range_collection.py +12 -13
- edc_reportable/post_migrate_signals.py +1 -1
- edc_reportable/utils/convert_units.py +11 -45
- edc_reportable/utils/get_normal_data_or_raise.py +2 -2
- edc_reportable/utils/load_data.py +4 -4
- edc_reportable/utils/update_grading_data.py +5 -5
- edc_review_dashboard/migrations/0001_initial.py +3 -2
- edc_review_dashboard/migrations/0006_alter_edcpermissions_device_created_and_more.py +49 -0
- edc_screening/age_evaluator.py +3 -3
- edc_screening/migrations/0001_initial.py +3 -2
- edc_screening/migrations/0005_alter_edcpermissions_device_created_and_more.py +49 -0
- edc_screening/model_mixins/eligibility_model_mixin.py +3 -4
- edc_screening/model_mixins/screening_fields_model_mixin.py +6 -8
- edc_search/model_mixins.py +2 -3
- edc_search/search_slug.py +9 -8
- edc_search/updater.py +2 -2
- edc_sites/migrations/0007_edcpermissions.py +3 -2
- edc_sites/migrations/0010_alter_edcpermissions_device_created_and_more.py +69 -0
- edc_sites/model_mixins/site_model_mixin.py +2 -2
- edc_sites/site.py +5 -5
- edc_sites/system_checks.py +1 -1
- edc_subject_dashboard/migrations/0001_initial.py +3 -2
- edc_subject_dashboard/migrations/0005_alter_edcpermissions_device_created_and_more.py +49 -0
- edc_subject_dashboard/requisition_report.py +6 -4
- edc_subject_dashboard/requisition_verifier.py +6 -6
- edc_subject_dashboard/templatetags/edc_subject_dashboard_extras.py +2 -2
- edc_subject_dashboard/view_mixins/subject_visit_view_mixin.py +7 -8
- edc_subject_dashboard/view_utils/subject_consent_listboard_button.py +3 -2
- edc_subject_dashboard/view_utils/timepoint_status_button.py +2 -2
- edc_timepoint/model_mixins.py +22 -20
- edc_transfer/model_mixins.py +4 -4
- edc_transfer/modeladmin_mixins.py +1 -1
- edc_unblinding/migrations/0001_initial.py +13 -13
- edc_unblinding/migrations/0014_alter_historicalunblindingrequest_action_identifier_and_more.py +291 -0
- edc_unblinding/migrations/0015_alter_historicalunblindingrequest_report_datetime_and_more.py +45 -0
- edc_unblinding/models/unblinding_request.py +2 -2
- edc_unblinding/models/unblinding_review.py +3 -3
- edc_utils/age.py +10 -16
- edc_visit_schedule/migrations/0001_initial.py +3 -3
- edc_visit_schedule/migrations/0002_auto_20190305_0123.py +3 -6
- edc_visit_schedule/migrations/0003_historicalvisitschedule_visitschedule.py +5 -4
- edc_visit_schedule/migrations/0015_historicalonschedule_offschedule_onschedule.py +10 -10
- edc_visit_schedule/migrations/0019_alter_historicalonschedule_device_created_and_more.py +229 -0
- edc_visit_schedule/migrations/0020_alter_historicalonschedule_onschedule_datetime_and_more.py +65 -0
- edc_visit_schedule/model_mixins/off_schedule_model_mixin.py +5 -4
- edc_visit_schedule/model_mixins/on_schedule_model_mixin.py +5 -4
- edc_visit_schedule/model_mixins/visit_schedule/visit_code_fields_model_mixin.py +1 -1
- edc_visit_schedule/models/subject_schedule_history.py +6 -6
- edc_visit_schedule/schedule/visit_collection.py +1 -1
- edc_visit_schedule/subject_schedule.py +5 -4
- edc_visit_schedule/view_mixins.py +2 -3
- edc_visit_schedule/visit/visit.py +3 -2
- edc_visit_tracking/migrations/0004_subjectvisit_subjectvisitmissedreasons_extra_value_and_more.py +13 -13
- edc_visit_tracking/migrations/0009_alter_historicalsubjectvisit_comments_and_more.py +450 -0
- edc_visit_tracking/migrations/0010_alter_historicalsubjectvisit_report_datetime_and_more.py +68 -0
- edc_visit_tracking/model_mixins/base/visit_methods_model_mixin.py +3 -3
- edc_visit_tracking/model_mixins/crfs/visit_tracking_crf_model_mixin.py +2 -2
- edc_visit_tracking/model_mixins/requisitions/visit_tracking_requisition_model_mixin.py +2 -2
- edc_visit_tracking/model_mixins/subject_visit_missed_model_mixin.py +2 -2
- edc_visit_tracking/model_mixins/visit_model_mixin/caretaker_fields_mixin.py +2 -3
- edc_visit_tracking/model_mixins/visit_model_mixin/previous_visit_model_mixin.py +1 -1
- edc_visit_tracking/model_mixins/visit_model_mixin/visit_model_fields_mixin.py +8 -11
- edc_visit_tracking/model_mixins/visit_model_mixin/visit_model_mixin.py +1 -1
- edc_visit_tracking/models/signals.py +1 -1
- edc_visit_tracking/models/subject_visit.py +1 -1
- edc_vitals/calculators/bmi.py +7 -5
- edc_vitals/utils.py +1 -1
- {clinicedc-2.0.6.dist-info → clinicedc-2.0.7.dist-info}/WHEEL +0 -0
- {clinicedc-2.0.6.dist-info → clinicedc-2.0.7.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from django.db import models
|
|
2
|
+
from django.utils import timezone
|
|
2
3
|
|
|
3
4
|
from edc_action_item.managers import (
|
|
4
5
|
ActionIdentifierModelManager,
|
|
@@ -9,7 +10,6 @@ from edc_identifier.model_mixins import UniqueSubjectIdentifierFieldMixin
|
|
|
9
10
|
from edc_model.validators import date_not_future, datetime_not_future
|
|
10
11
|
from edc_protocol.validators import datetime_not_before_study_start
|
|
11
12
|
from edc_sites.model_mixins import SiteModelMixin
|
|
12
|
-
from edc_utils import get_utcnow
|
|
13
13
|
|
|
14
14
|
from ...constants import DEATH_REPORT_ACTION
|
|
15
15
|
|
|
@@ -27,7 +27,7 @@ class SimpleDeathReportModelMixin(
|
|
|
27
27
|
report_datetime = models.DateTimeField(
|
|
28
28
|
verbose_name="Report Date",
|
|
29
29
|
validators=[datetime_not_before_study_start, datetime_not_future],
|
|
30
|
-
default=
|
|
30
|
+
default=timezone.now,
|
|
31
31
|
)
|
|
32
32
|
|
|
33
33
|
death_datetime = models.DateTimeField(
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
from django.db import models
|
|
2
|
+
from django.utils import timezone
|
|
2
3
|
|
|
3
4
|
from edc_constants.choices import YES_NO, YES_NO_UNKNOWN
|
|
4
5
|
from edc_constants.constants import NOT_APPLICABLE
|
|
5
6
|
from edc_identifier.model_mixins import NonUniqueSubjectIdentifierFieldMixin
|
|
6
7
|
from edc_model import models as edc_models
|
|
7
8
|
from edc_model.validators import date_not_future, datetime_not_future
|
|
9
|
+
from edc_model_fields.fields import IsDateEstimatedField
|
|
8
10
|
from edc_protocol.validators import (
|
|
9
11
|
date_not_before_study_start,
|
|
10
12
|
datetime_not_before_study_start,
|
|
11
13
|
)
|
|
12
|
-
from edc_utils import get_utcnow
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
class HospitalizationModelMixin(NonUniqueSubjectIdentifierFieldMixin, models.Model):
|
|
16
17
|
report_datetime = models.DateTimeField(
|
|
17
18
|
verbose_name="Report Date",
|
|
18
19
|
validators=[datetime_not_before_study_start, datetime_not_future],
|
|
19
|
-
default=
|
|
20
|
+
default=timezone.now,
|
|
20
21
|
)
|
|
21
22
|
|
|
22
23
|
have_details = models.CharField(
|
|
@@ -30,7 +31,7 @@ class HospitalizationModelMixin(NonUniqueSubjectIdentifierFieldMixin, models.Mod
|
|
|
30
31
|
validators=[date_not_future, date_not_before_study_start],
|
|
31
32
|
)
|
|
32
33
|
|
|
33
|
-
admitted_date_estimated =
|
|
34
|
+
admitted_date_estimated = IsDateEstimatedField(
|
|
34
35
|
verbose_name="Is this date estimated?",
|
|
35
36
|
)
|
|
36
37
|
|
|
@@ -4,6 +4,7 @@ from django.contrib import admin
|
|
|
4
4
|
from django.contrib.admin import display
|
|
5
5
|
from django.template.loader import render_to_string
|
|
6
6
|
from django.urls import NoReverseMatch, reverse
|
|
7
|
+
from django.utils import timezone
|
|
7
8
|
from django_audit_fields.admin import audit_fieldset_tuple
|
|
8
9
|
|
|
9
10
|
from edc_action_item.fieldsets import action_fieldset_tuple
|
|
@@ -12,7 +13,6 @@ from edc_constants.constants import CANCELLED, OTHER
|
|
|
12
13
|
from edc_model_admin.dashboard import ModelAdminSubjectDashboardMixin
|
|
13
14
|
from edc_model_admin.list_filters import ReportDateListFilter
|
|
14
15
|
from edc_pdf_reports.admin import PdfButtonModelAdminMixin, print_selected_to_pdf_action
|
|
15
|
-
from edc_utils import get_utcnow
|
|
16
16
|
|
|
17
17
|
from ..utils import get_adverse_event_app_label
|
|
18
18
|
from .list_filters import CauseOfDeathListFilter, DeathDateListFilter
|
|
@@ -111,14 +111,14 @@ class DeathReportModelAdminMixin(
|
|
|
111
111
|
def report_datetime_with_ago(self, obj=None):
|
|
112
112
|
return render_to_string(
|
|
113
113
|
"edc_adverse_event/datetime_with_ago.html",
|
|
114
|
-
dict(utc_date=
|
|
114
|
+
dict(utc_date=timezone.now().date, report_datetime=obj.report_datetime),
|
|
115
115
|
)
|
|
116
116
|
|
|
117
117
|
@display(description="Death date", ordering="death_datetime")
|
|
118
118
|
def death_datetime_with_ago(self, obj=None):
|
|
119
119
|
return render_to_string(
|
|
120
120
|
"edc_adverse_event/datetime_with_ago.html",
|
|
121
|
-
dict(utc_date=
|
|
121
|
+
dict(utc_date=timezone.now().date, report_datetime=obj.death_datetime),
|
|
122
122
|
)
|
|
123
123
|
|
|
124
124
|
@display(description="Action item", ordering="action_identifier")
|
|
@@ -2,17 +2,17 @@ from django.core.exceptions import ObjectDoesNotExist
|
|
|
2
2
|
from django.db import transaction
|
|
3
3
|
from django.db.models.signals import m2m_changed, post_delete, post_save
|
|
4
4
|
from django.dispatch.dispatcher import receiver
|
|
5
|
+
from django.utils import timezone
|
|
5
6
|
|
|
6
7
|
from edc_constants.constants import NO, YES
|
|
7
8
|
from edc_notification.models import Notification
|
|
8
|
-
from edc_utils import get_utcnow
|
|
9
9
|
|
|
10
10
|
from ..constants import AE_TMG_ACTION, DEATH_REPORT_TMG_ACTION, TMG
|
|
11
11
|
from ..utils import get_ae_model
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
@receiver(m2m_changed, weak=False, dispatch_uid="update_ae_notifications_for_tmg_group")
|
|
15
|
-
def update_ae_notifications_for_tmg_group(action, instance, **kwargs):
|
|
15
|
+
def update_ae_notifications_for_tmg_group(action, instance, **kwargs):
|
|
16
16
|
if getattr(instance, "userprofile", None):
|
|
17
17
|
try:
|
|
18
18
|
tmg_ae_notification = Notification.objects.get(name=AE_TMG_ACTION)
|
|
@@ -29,7 +29,7 @@ def update_ae_notifications_for_tmg_group(action, instance, **kwargs): # noqa:
|
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
@receiver(post_save, weak=False, dispatch_uid="update_ae_initial_for_susar")
|
|
32
|
-
def update_ae_initial_for_susar(sender, instance, raw, update_fields, **kwargs):
|
|
32
|
+
def update_ae_initial_for_susar(sender, instance, raw, update_fields, **kwargs):
|
|
33
33
|
if not raw and not update_fields:
|
|
34
34
|
try:
|
|
35
35
|
ae_susar_model_cls = get_ae_model("AeSusar")
|
|
@@ -55,7 +55,7 @@ def update_ae_initial_for_susar(sender, instance, raw, update_fields, **kwargs):
|
|
|
55
55
|
weak=False,
|
|
56
56
|
dispatch_uid="update_ae_initial_susar_reported",
|
|
57
57
|
)
|
|
58
|
-
def update_ae_initial_susar_reported(sender, instance, raw, update_fields, **kwargs):
|
|
58
|
+
def update_ae_initial_susar_reported(sender, instance, raw, update_fields, **kwargs):
|
|
59
59
|
if not raw and not update_fields:
|
|
60
60
|
try:
|
|
61
61
|
ae_initial_model_cls = get_ae_model("AeInitial")
|
|
@@ -72,12 +72,12 @@ def update_ae_initial_susar_reported(sender, instance, raw, update_fields, **kwa
|
|
|
72
72
|
ae_susar_model_cls.objects.get(ae_initial=instance)
|
|
73
73
|
except ObjectDoesNotExist:
|
|
74
74
|
ae_susar_model_cls.objects.create(
|
|
75
|
-
ae_initial=instance, submitted_datetime=
|
|
75
|
+
ae_initial=instance, submitted_datetime=timezone.now()
|
|
76
76
|
)
|
|
77
77
|
|
|
78
78
|
|
|
79
79
|
@receiver(post_delete, weak=False, dispatch_uid="post_delete_ae_susar")
|
|
80
|
-
def post_delete_ae_susar(instance, **kwargs):
|
|
80
|
+
def post_delete_ae_susar(instance, **kwargs):
|
|
81
81
|
try:
|
|
82
82
|
ae_susar_model_cls = get_ae_model("AeSusar")
|
|
83
83
|
except LookupError:
|
|
@@ -93,7 +93,7 @@ def post_delete_ae_susar(instance, **kwargs): # noqa: ARG001
|
|
|
93
93
|
|
|
94
94
|
|
|
95
95
|
@receiver(m2m_changed, weak=False, dispatch_uid="update_death_notifications_for_tmg_group")
|
|
96
|
-
def update_death_notifications_for_tmg_group(action, instance, **kwargs):
|
|
96
|
+
def update_death_notifications_for_tmg_group(action, instance, **kwargs):
|
|
97
97
|
if getattr(instance, "userprofile", None):
|
|
98
98
|
try:
|
|
99
99
|
tmg_death_notification = Notification.objects.get(name=DEATH_REPORT_TMG_ACTION)
|
|
@@ -10,6 +10,7 @@ from django.conf import settings
|
|
|
10
10
|
from django.contrib.messages import ERROR
|
|
11
11
|
from django.core.exceptions import ObjectDoesNotExist
|
|
12
12
|
from django.template.loader import select_template
|
|
13
|
+
from django.utils import timezone
|
|
13
14
|
from django.utils.html import format_html
|
|
14
15
|
from django.utils.safestring import mark_safe
|
|
15
16
|
from django.utils.translation import gettext as _
|
|
@@ -17,7 +18,7 @@ from django.utils.translation import gettext as _
|
|
|
17
18
|
from edc_action_item.utils import get_reference_obj
|
|
18
19
|
from edc_constants.constants import CLOSED, OPEN, OTHER, YES
|
|
19
20
|
from edc_model_admin.utils import add_to_messages_once
|
|
20
|
-
from edc_utils import escape_braces
|
|
21
|
+
from edc_utils import escape_braces
|
|
21
22
|
|
|
22
23
|
from ..constants import (
|
|
23
24
|
AE_TMG_ACTION,
|
|
@@ -81,7 +82,7 @@ def select_description_template(model):
|
|
|
81
82
|
|
|
82
83
|
@register.inclusion_tag(select_description_template("aeinitial"), takes_context=True)
|
|
83
84
|
def format_ae_description(context, ae_initial, wrap_length):
|
|
84
|
-
context["utc_date"] =
|
|
85
|
+
context["utc_date"] = timezone.now().date()
|
|
85
86
|
context["SHORT_DATE_FORMAT"] = settings.SHORT_DATE_FORMAT
|
|
86
87
|
context["OTHER"] = OTHER
|
|
87
88
|
context["YES"] = YES
|
|
@@ -103,7 +104,7 @@ def format_ae_description(context, ae_initial, wrap_length):
|
|
|
103
104
|
@register.inclusion_tag(select_description_template("aefollowup"), takes_context=True)
|
|
104
105
|
def format_ae_followup_description(context, ae_followup, wrap_length):
|
|
105
106
|
context["AE_WITHDRAWN"] = AE_WITHDRAWN
|
|
106
|
-
context["utc_date"] =
|
|
107
|
+
context["utc_date"] = timezone.now().date()
|
|
107
108
|
context["SHORT_DATE_FORMAT"] = settings.SHORT_DATE_FORMAT
|
|
108
109
|
context["OTHER"] = OTHER
|
|
109
110
|
context["YES"] = YES
|
|
@@ -131,7 +132,7 @@ def format_ae_followup_description(context, ae_followup, wrap_length):
|
|
|
131
132
|
|
|
132
133
|
@register.inclusion_tag(select_description_template("aesusar"), takes_context=True)
|
|
133
134
|
def format_ae_susar_description(context, ae_susar, wrap_length):
|
|
134
|
-
context["utc_date"] =
|
|
135
|
+
context["utc_date"] = timezone.now().date()
|
|
135
136
|
context["SHORT_DATE_FORMAT"] = settings.SHORT_DATE_FORMAT
|
|
136
137
|
context["OTHER"] = OTHER
|
|
137
138
|
context["YES"] = YES
|
|
@@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Any
|
|
|
4
4
|
|
|
5
5
|
from django.core.exceptions import ObjectDoesNotExist
|
|
6
6
|
from django.template.loader import render_to_string
|
|
7
|
+
from django.utils import timezone
|
|
7
8
|
from django.utils.html import format_html
|
|
8
9
|
from django.utils.safestring import mark_safe
|
|
9
10
|
|
|
@@ -12,7 +13,6 @@ from edc_dashboard.view_mixins import EdcViewMixin
|
|
|
12
13
|
from edc_listboard.view_mixins import ListboardFilterViewMixin, SearchFormViewMixin
|
|
13
14
|
from edc_listboard.views import ListboardView as BaseListboardView
|
|
14
15
|
from edc_navbar import NavbarViewMixin
|
|
15
|
-
from edc_utils import get_utcnow
|
|
16
16
|
|
|
17
17
|
from ...constants import AE_INITIAL_ACTION
|
|
18
18
|
from ...pdf_reports import AePdfReport
|
|
@@ -43,9 +43,7 @@ class AeListboardViewMixin(
|
|
|
43
43
|
|
|
44
44
|
listboard_instructions = format_html(
|
|
45
45
|
"{}",
|
|
46
|
-
mark_safe(
|
|
47
|
-
render_to_string("edc_adverse_event/ae/ae_listboard_instructions.html")
|
|
48
|
-
), # nosec B703 B308,
|
|
46
|
+
mark_safe(render_to_string("edc_adverse_event/ae/ae_listboard_instructions.html")), # nosec B703 B308,
|
|
49
47
|
)
|
|
50
48
|
navbar_selected_item = "ae_home"
|
|
51
49
|
ordering = "-report_datetime"
|
|
@@ -78,7 +76,7 @@ class AeListboardViewMixin(
|
|
|
78
76
|
def get_context_data(self, **kwargs) -> dict[str, Any]:
|
|
79
77
|
kwargs.update(
|
|
80
78
|
AE_INITIAL_ACTION=AE_INITIAL_ACTION,
|
|
81
|
-
utc_date=
|
|
79
|
+
utc_date=timezone.now().date(),
|
|
82
80
|
**self.add_url_to_context(
|
|
83
81
|
new_key="ae_home_url",
|
|
84
82
|
existing_key=self.home_url,
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
from typing import TYPE_CHECKING, Any
|
|
4
4
|
|
|
5
5
|
from django.core.exceptions import ObjectDoesNotExist
|
|
6
|
+
from django.utils import timezone
|
|
6
7
|
from django.utils.html import format_html
|
|
7
8
|
from django.utils.safestring import mark_safe
|
|
8
9
|
|
|
@@ -11,7 +12,6 @@ from edc_dashboard.view_mixins import EdcViewMixin
|
|
|
11
12
|
from edc_listboard.view_mixins import ListboardFilterViewMixin, SearchFormViewMixin
|
|
12
13
|
from edc_listboard.views import ListboardView as BaseListboardView
|
|
13
14
|
from edc_navbar import NavbarViewMixin
|
|
14
|
-
from edc_utils import get_utcnow
|
|
15
15
|
|
|
16
16
|
from ...constants import DEATH_REPORT_ACTION
|
|
17
17
|
from ...pdf_reports import DeathPdfReport
|
|
@@ -40,25 +40,23 @@ class DeathReportListboardViewMixin(
|
|
|
40
40
|
listboard_view_permission_codename = "edc_adverse_event.view_ae_listboard"
|
|
41
41
|
listboard_instructions = format_html(
|
|
42
42
|
"{}",
|
|
43
|
-
mark_safe(
|
|
44
|
-
"edc_adverse_event/ae/death_report_listboard_instructions.html"
|
|
45
|
-
), # nosec B703 B308
|
|
43
|
+
mark_safe("edc_adverse_event/ae/death_report_listboard_instructions.html"), # nosec B703 B308
|
|
46
44
|
)
|
|
47
45
|
|
|
48
46
|
navbar_selected_item = "ae_home"
|
|
49
47
|
ordering = "-report_datetime"
|
|
50
48
|
paginate_by = 25
|
|
51
49
|
search_form_url = "death_report_listboard_url"
|
|
52
|
-
action_type_names =
|
|
50
|
+
action_type_names = (DEATH_REPORT_ACTION,)
|
|
53
51
|
|
|
54
|
-
search_fields =
|
|
52
|
+
search_fields = (
|
|
55
53
|
"subject_identifier",
|
|
56
54
|
"action_identifier",
|
|
57
55
|
"parent_action_item__action_identifier",
|
|
58
56
|
"related_action_item__action_identifier",
|
|
59
57
|
"user_created",
|
|
60
58
|
"user_modified",
|
|
61
|
-
|
|
59
|
+
)
|
|
62
60
|
|
|
63
61
|
def get(self, request, *args, **kwargs):
|
|
64
62
|
if request.GET.get("pdf"):
|
|
@@ -71,7 +69,7 @@ class DeathReportListboardViewMixin(
|
|
|
71
69
|
def get_context_data(self, **kwargs) -> dict[str, Any]:
|
|
72
70
|
kwargs.update(
|
|
73
71
|
DEATH_REPORT_ACTION=DEATH_REPORT_ACTION,
|
|
74
|
-
utc_date=
|
|
72
|
+
utc_date=timezone.now().date(),
|
|
75
73
|
**self.add_url_to_context(
|
|
76
74
|
new_key="ae_home_url",
|
|
77
75
|
existing_key=self.home_url,
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
from typing import TYPE_CHECKING, Any
|
|
4
4
|
|
|
5
5
|
from django.db.models import Min
|
|
6
|
+
from django.utils import timezone
|
|
6
7
|
|
|
7
8
|
from edc_constants.constants import CLOSED, NEW, OPEN
|
|
8
9
|
from edc_dashboard.view_mixins import EdcViewMixin
|
|
@@ -10,7 +11,6 @@ from edc_listboard.view_mixins import ListboardFilterViewMixin, SearchFormViewMi
|
|
|
10
11
|
from edc_listboard.views import ListboardView as BaseListboardView
|
|
11
12
|
from edc_navbar import NavbarViewMixin
|
|
12
13
|
from edc_navbar.get_default_navbar import get_default_navbar
|
|
13
|
-
from edc_utils import get_utcnow
|
|
14
14
|
|
|
15
15
|
from ...constants import (
|
|
16
16
|
AE_TMG_ACTION,
|
|
@@ -69,7 +69,7 @@ class TmgAeListboardViewMixin(
|
|
|
69
69
|
def get_context_data(self, **kwargs) -> dict[str, Any]:
|
|
70
70
|
kwargs.update(
|
|
71
71
|
AE_TMG_ACTION=AE_TMG_ACTION,
|
|
72
|
-
utc_date=
|
|
72
|
+
utc_date=timezone.now().date(),
|
|
73
73
|
subject_identifier=self.kwargs.get("subject_identifier"),
|
|
74
74
|
)
|
|
75
75
|
return super().get_context_data(**kwargs)
|
|
@@ -2,11 +2,12 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import TYPE_CHECKING, Any
|
|
4
4
|
|
|
5
|
+
from django.utils import timezone
|
|
6
|
+
|
|
5
7
|
from edc_dashboard.view_mixins import EdcViewMixin
|
|
6
8
|
from edc_listboard.view_mixins import ListboardFilterViewMixin, SearchFormViewMixin
|
|
7
9
|
from edc_listboard.views import ListboardView as BaseListboardView
|
|
8
10
|
from edc_navbar import NavbarViewMixin
|
|
9
|
-
from edc_utils import get_utcnow
|
|
10
11
|
|
|
11
12
|
from ...constants import (
|
|
12
13
|
AE_FOLLOWUP_ACTION,
|
|
@@ -57,7 +58,7 @@ class SummaryListboardView(
|
|
|
57
58
|
]
|
|
58
59
|
|
|
59
60
|
def get_context_data(self, **kwargs) -> dict[str, Any]:
|
|
60
|
-
kwargs.update(AE_TMG_ACTION=AE_TMG_ACTION, utc_date=
|
|
61
|
+
kwargs.update(AE_TMG_ACTION=AE_TMG_ACTION, utc_date=timezone.now().date())
|
|
61
62
|
return super().get_context_data(**kwargs)
|
|
62
63
|
|
|
63
64
|
def get_queryset_filter_options(self, request, *args, **kwargs) -> tuple[Q, dict]:
|
|
@@ -7,6 +7,7 @@ from django.contrib import admin
|
|
|
7
7
|
from django.db.models import DurationField, ExpressionWrapper, F
|
|
8
8
|
from django.template.loader import render_to_string
|
|
9
9
|
from django.urls import reverse
|
|
10
|
+
from django.utils import timezone
|
|
10
11
|
from django.utils.html import format_html
|
|
11
12
|
from django.utils.translation import gettext as _
|
|
12
13
|
from django_audit_fields.admin import audit_fieldset_tuple
|
|
@@ -19,7 +20,6 @@ from edc_document_status.modeladmin_mixins import DocumentStatusModelAdminMixin
|
|
|
19
20
|
from edc_model_admin.dashboard import ModelAdminSubjectDashboardMixin
|
|
20
21
|
from edc_model_admin.history import SimpleHistoryAdmin
|
|
21
22
|
from edc_sites.admin import SiteModelAdminMixin
|
|
22
|
-
from edc_utils import get_utcnow
|
|
23
23
|
from edc_visit_schedule.admin import ScheduleStatusListFilter
|
|
24
24
|
from edc_visit_schedule.exceptions import OnScheduleError
|
|
25
25
|
from edc_visit_schedule.fieldsets import (
|
|
@@ -290,7 +290,7 @@ class AppointmentAdmin(
|
|
|
290
290
|
|
|
291
291
|
def get_queryset(self, request):
|
|
292
292
|
qs = super().get_queryset(request)
|
|
293
|
-
now =
|
|
293
|
+
now = timezone.now().replace(second=59, hour=23, minute=59)
|
|
294
294
|
return qs.annotate(
|
|
295
295
|
appt_timepoint_delta=ExpressionWrapper(
|
|
296
296
|
(F("appt_datetime") - F("timepoint_datetime")),
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
from dateutil.relativedelta import relativedelta
|
|
4
4
|
from django.contrib.admin import SimpleListFilter
|
|
5
5
|
from django.db.models import QuerySet
|
|
6
|
+
from django.utils import timezone
|
|
6
7
|
from django.utils.translation import gettext as _
|
|
7
8
|
|
|
8
9
|
from edc_appointment.choices import APPT_STATUS
|
|
@@ -18,7 +19,6 @@ from edc_appointment.constants import (
|
|
|
18
19
|
LT_30_DAYS,
|
|
19
20
|
)
|
|
20
21
|
from edc_model_admin.list_filters import FutureDateListFilter
|
|
21
|
-
from edc_utils import get_utcnow
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
class AppointmentListFilter(FutureDateListFilter):
|
|
@@ -62,7 +62,7 @@ class AppointmentOverdueListFilter(SimpleListFilter):
|
|
|
62
62
|
)
|
|
63
63
|
|
|
64
64
|
def queryset(self, request, queryset) -> QuerySet | None:
|
|
65
|
-
now =
|
|
65
|
+
now = timezone.now().replace(second=59, hour=23, minute=59)
|
|
66
66
|
qs = None
|
|
67
67
|
if self.value() == LT_30_DAYS:
|
|
68
68
|
qs = queryset.filter(
|
|
@@ -6,6 +6,7 @@ from typing import TYPE_CHECKING, Any
|
|
|
6
6
|
from django.apps import apps as django_apps
|
|
7
7
|
from django.conf import settings
|
|
8
8
|
from django.urls import reverse
|
|
9
|
+
from django.utils import timezone
|
|
9
10
|
from django.utils.html import format_html
|
|
10
11
|
from django.utils.safestring import mark_safe
|
|
11
12
|
from django.utils.translation import gettext_lazy as _
|
|
@@ -16,7 +17,7 @@ from edc_form_validators import INVALID_ERROR
|
|
|
16
17
|
from edc_form_validators.form_validator import FormValidator
|
|
17
18
|
from edc_metadata.metadata_helper import MetadataHelperMixin
|
|
18
19
|
from edc_sites.form_validator_mixin import SiteFormValidatorMixin
|
|
19
|
-
from edc_utils import formatted_datetime,
|
|
20
|
+
from edc_utils import formatted_datetime, to_utc
|
|
20
21
|
from edc_utils.date import to_local
|
|
21
22
|
from edc_visit_schedule.site_visit_schedules import site_visit_schedules
|
|
22
23
|
from edc_visit_schedule.subject_schedule import NotOnScheduleError
|
|
@@ -136,19 +137,23 @@ class AppointmentFormValidator(
|
|
|
136
137
|
self.instance, "id", None
|
|
137
138
|
):
|
|
138
139
|
previous_appt = get_previous_appointment(self.instance, include_interim=True)
|
|
139
|
-
if
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
140
|
+
if (
|
|
141
|
+
previous_appt
|
|
142
|
+
and previous_appt.appt_status
|
|
143
|
+
not in [
|
|
144
|
+
CANCELLED_APPT,
|
|
145
|
+
SKIPPED_APPT,
|
|
146
|
+
]
|
|
147
|
+
and not previous_appt.related_visit
|
|
148
|
+
):
|
|
149
|
+
self.raise_validation_error(
|
|
150
|
+
message=(
|
|
151
|
+
"A previous appointment requires a visit report. "
|
|
152
|
+
f"Update appointment {previous_appt.visit_code}."
|
|
153
|
+
f"{previous_appt.visit_code_sequence} first."
|
|
154
|
+
),
|
|
155
|
+
error_code=INVALID_PREVIOUS_VISIT_MISSING,
|
|
156
|
+
)
|
|
152
157
|
return True
|
|
153
158
|
|
|
154
159
|
def validate_appt_sequence(self: Any) -> bool:
|
|
@@ -158,33 +163,45 @@ class AppointmentFormValidator(
|
|
|
158
163
|
Check if previous appointment appt_status is NEW_APPT
|
|
159
164
|
|
|
160
165
|
"""
|
|
161
|
-
if
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
.
|
|
177
|
-
)
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
166
|
+
if (
|
|
167
|
+
self.cleaned_data.get("appt_status")
|
|
168
|
+
in [
|
|
169
|
+
IN_PROGRESS_APPT,
|
|
170
|
+
INCOMPLETE_APPT,
|
|
171
|
+
COMPLETE_APPT,
|
|
172
|
+
]
|
|
173
|
+
and self.instance.previous
|
|
174
|
+
) and (
|
|
175
|
+
obj := (
|
|
176
|
+
self.appointment_model_cls.objects.filter(
|
|
177
|
+
subject_identifier=self.subject_identifier,
|
|
178
|
+
visit_schedule_name=self.instance.visit_schedule_name,
|
|
179
|
+
schedule_name=self.instance.schedule_name,
|
|
180
|
+
appt_status=NEW_APPT,
|
|
181
|
+
appt_datetime__lt=self.instance.appt_datetime,
|
|
182
|
+
)
|
|
183
|
+
.order_by("timepoint", "visit_code_sequence")
|
|
184
|
+
.first()
|
|
185
|
+
)
|
|
186
|
+
):
|
|
187
|
+
errmsg = (
|
|
188
|
+
"A previous appointment requires updating. "
|
|
189
|
+
"Update appointment %(visit_code)s."
|
|
190
|
+
"%(visit_code_sequence)s first."
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
self.raise_validation_error(
|
|
194
|
+
{
|
|
195
|
+
"__all__": _(
|
|
196
|
+
errmsg
|
|
197
|
+
% dict(
|
|
198
|
+
visit_code=obj.visit_code,
|
|
199
|
+
visit_code_sequence=obj.visit_code_sequence,
|
|
200
|
+
)
|
|
187
201
|
)
|
|
202
|
+
},
|
|
203
|
+
INVALID_PREVIOUS_APPOINTMENT_NOT_UPDATED,
|
|
204
|
+
)
|
|
188
205
|
return True
|
|
189
206
|
|
|
190
207
|
def validate_timepoint(self: Any):
|
|
@@ -202,12 +219,15 @@ class AppointmentFormValidator(
|
|
|
202
219
|
def validate_not_future_appt_datetime(self: Any) -> None:
|
|
203
220
|
appt_datetime = self.cleaned_data.get("appt_datetime")
|
|
204
221
|
appt_status = self.cleaned_data.get("appt_status")
|
|
205
|
-
if
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
222
|
+
if (
|
|
223
|
+
appt_datetime
|
|
224
|
+
and appt_status != NEW_APPT
|
|
225
|
+
and to_utc(appt_datetime) > timezone.now()
|
|
226
|
+
):
|
|
227
|
+
self.raise_validation_error(
|
|
228
|
+
{"appt_datetime": "Cannot be a future date/time."},
|
|
229
|
+
INVALID_APPT_DATE,
|
|
230
|
+
)
|
|
211
231
|
|
|
212
232
|
def validate_appt_datetime_not_before_consent_datetime(self: Any) -> None:
|
|
213
233
|
if (
|
|
@@ -291,42 +311,46 @@ class AppointmentFormValidator(
|
|
|
291
311
|
def validate_appt_datetime_not_before_previous_appt_datetime(self):
|
|
292
312
|
appt_datetime = self.cleaned_data.get("appt_datetime")
|
|
293
313
|
appt_status = self.cleaned_data.get("appt_status")
|
|
294
|
-
if
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
}
|
|
308
|
-
INVALID_APPT_DATE,
|
|
314
|
+
if (
|
|
315
|
+
appt_datetime
|
|
316
|
+
and appt_status
|
|
317
|
+
and appt_status != NEW_APPT
|
|
318
|
+
and self.instance.relative_previous
|
|
319
|
+
and to_utc(appt_datetime) < self.instance.relative_previous.appt_datetime
|
|
320
|
+
):
|
|
321
|
+
formatted_date = formatted_datetime(self.instance.relative_previous.appt_datetime)
|
|
322
|
+
self.raise_validation_error(
|
|
323
|
+
{
|
|
324
|
+
"appt_datetime": (
|
|
325
|
+
"Cannot be before previous appointment. Previous appointment "
|
|
326
|
+
f"is {self.instance.relative_previous.visit_label} "
|
|
327
|
+
f"on {formatted_date}."
|
|
309
328
|
)
|
|
329
|
+
},
|
|
330
|
+
INVALID_APPT_DATE,
|
|
331
|
+
)
|
|
310
332
|
|
|
311
333
|
def validate_appt_datetime_not_after_next_appt_datetime(self) -> None:
|
|
312
334
|
appt_datetime = self.cleaned_data.get("appt_datetime")
|
|
313
335
|
appt_status = self.cleaned_data.get("appt_status")
|
|
314
|
-
if
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
}
|
|
328
|
-
INVALID_APPT_DATE,
|
|
336
|
+
if (
|
|
337
|
+
appt_datetime
|
|
338
|
+
and appt_status
|
|
339
|
+
and appt_status != NEW_APPT
|
|
340
|
+
and self.instance.relative_next
|
|
341
|
+
and to_utc(appt_datetime) > self.instance.relative_next.appt_datetime
|
|
342
|
+
):
|
|
343
|
+
formatted_date = formatted_datetime(self.instance.relative_next.appt_datetime)
|
|
344
|
+
self.raise_validation_error(
|
|
345
|
+
{
|
|
346
|
+
"appt_datetime": (
|
|
347
|
+
"Cannot be after next appointment. Next appointment is "
|
|
348
|
+
f"{self.instance.relative_next.visit_label} "
|
|
349
|
+
f"on {formatted_date}."
|
|
329
350
|
)
|
|
351
|
+
},
|
|
352
|
+
INVALID_APPT_DATE,
|
|
353
|
+
)
|
|
330
354
|
|
|
331
355
|
def validate_appt_incomplete_and_visit_report(self: Any) -> None:
|
|
332
356
|
"""Require a visit report, at least, if wanting to set appt_status
|
|
@@ -502,12 +526,14 @@ class AppointmentFormValidator(
|
|
|
502
526
|
|
|
503
527
|
Is this still used?
|
|
504
528
|
"""
|
|
505
|
-
if
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
529
|
+
if (
|
|
530
|
+
self.cleaned_data.get("facility_name")
|
|
531
|
+
and self.cleaned_data.get("facility_name") not in get_facilities()
|
|
532
|
+
):
|
|
533
|
+
self.raise_validation_error(
|
|
534
|
+
{"__all__": f"Facility '{self.facility_name}' does not exist."},
|
|
535
|
+
INVALID_ERROR,
|
|
536
|
+
)
|
|
511
537
|
|
|
512
538
|
def validate_appt_type(self):
|
|
513
539
|
self.not_applicable_if(SKIPPED_APPT, field="appt_status", field_applicable="appt_type")
|