clinicedc 2.0.6__py3-none-any.whl → 2.0.8__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.8.dist-info}/METADATA +2 -2
- {clinicedc-2.0.6.dist-info → clinicedc-2.0.8.dist-info}/RECORD +489 -441
- {clinicedc-2.0.6.dist-info → clinicedc-2.0.8.dist-info}/WHEEL +1 -1
- edc_action_item/action.py +1 -1
- edc_action_item/action_item_notification.py +2 -2
- edc_action_item/auths.py +37 -32
- 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 +5 -6
- edc_action_item/models/reference.py +2 -2
- edc_action_item/models/signals.py +22 -23
- edc_action_item/post_migrate_signals.py +1 -1
- edc_action_item/send_email.py +0 -85
- edc_action_item/site_action_items.py +5 -9
- edc_action_item/utils.py +3 -3
- edc_adherence/migrations/0005_alter_nonadherencereasons_extra_value_and_more.py +36 -0
- edc_adherence/model_mixins.py +1 -1
- edc_adverse_event/auths.py +55 -51
- 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/ae_tmg/ae_tmg_methods_model_mixin.py +2 -4
- 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/auths.py +14 -10
- edc_appointment/creators/appointment_creator.py +1 -1
- edc_appointment/creators/appointments_creator.py +1 -1
- 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/appointment_methods_model_mixin.py +2 -3
- edc_appointment/model_mixins/appointment_model_mixin.py +31 -28
- edc_appointment/model_mixins/window_period_model_mixin.py +6 -7
- edc_appointment/models/appointment.py +1 -1
- edc_appointment/models/signals.py +44 -35
- edc_appointment/utils.py +19 -24
- edc_appointment/view_utils/appointment_button.py +2 -2
- edc_auth/admin/user_admin.py +1 -1
- edc_auth/auth_objects/__init__.py +2 -20
- edc_auth/auth_objects/default_groups.py +13 -11
- edc_auth/auth_objects/default_roles.py +26 -24
- edc_auth/auth_updater/auth_updater.py +13 -2
- edc_auth/auth_updater/group_updater.py +12 -10
- edc_auth/auth_updater/role_updater.py +2 -2
- edc_auth/constants.py +10 -0
- edc_auth/import_users.py +3 -3
- 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/models/user_profile.py +14 -11
- edc_auth/post_migrate_signals.py +1 -1
- edc_auth/site_auths.py +80 -67
- edc_consent/actions.py +4 -5
- edc_consent/auths.py +18 -12
- 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_constants/constants.py +1 -0
- edc_crf/auths.py +5 -0
- edc_crf/migrations/0001_initial.py +3 -2
- edc_crf/migrations/0009_alter_crfstatus_device_created_and_more.py +54 -0
- edc_dashboard/auths.py +10 -6
- 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_dashboard/url_config.py +92 -83
- edc_dashboard/url_names.py +4 -4
- edc_dashboard/view_mixins/url_request_context_mixin.py +6 -5
- edc_data_manager/action_items.py +4 -6
- edc_data_manager/admin/actions.py +5 -5
- edc_data_manager/admin/data_query_admin.py +12 -11
- edc_data_manager/auths.py +37 -34
- 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/query_rule_wrapper.py +7 -7
- 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 +7 -5
- edc_export/auths.py +32 -28
- 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 +17 -15
- 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/auths.py +8 -3
- edc_facility/facility.py +16 -22
- 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_label/custom_label_condition.py +11 -8
- edc_form_label/form_label.py +1 -1
- edc_form_runners/auths.py +11 -6
- 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_form_validators/applicable_field_validator.py +7 -6
- edc_form_validators/base_form_validator.py +8 -9
- edc_form_validators/other_specify_field_validator.py +2 -8
- edc_form_validators/required_field_validator.py +19 -16
- 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/research_identifier.py +11 -10
- edc_identifier/simple_identifier.py +9 -5
- edc_identifier/subject_identifier.py +3 -2
- edc_lab/auths.py +26 -23
- edc_lab/lab/aliquot_creator.py +5 -8
- edc_lab/lab/primary_aliquot.py +14 -5
- 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 +13 -16
- 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/aliquot.py +2 -2
- edc_lab/models/box.py +1 -1
- edc_lab/models/box_item.py +6 -7
- edc_lab/models/manifest/manifest.py +3 -3
- edc_lab/models/manifest/manifest_item.py +7 -7
- 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/auths.py +16 -11
- 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/calculate_missing.py +8 -8
- edc_lab_results/form_validator_mixins/blood_results_form_validator_mixin.py +2 -2
- edc_lab_results/get_summary.py +26 -25
- edc_lab_results/model_mixins/blood_result_model_mixin.py +9 -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/auths.py +6 -1
- edc_label/label_template.py +8 -8
- 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/load_model_data.py +3 -3
- edc_list_data/model_mixins.py +12 -4
- edc_list_data/post_migrate_signals.py +1 -1
- edc_list_data/preload_data.py +4 -4
- edc_list_data/row.py +1 -1
- edc_list_data/site_list_data.py +6 -5
- edc_listboard/migrations/0001_initial.py +3 -2
- edc_listboard/migrations/0007_alter_listboard_device_created_and_more.py +49 -0
- edc_locator/auths.py +18 -13
- 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/auths.py +11 -7
- edc_metadata/metadata/metadata.py +1 -1
- edc_metadata/metadata_rules/crf/crf_rule.py +1 -1
- edc_metadata/metadata_rules/decorators.py +1 -1
- edc_metadata/metadata_rules/metadata_rule_evaluator.py +5 -3
- edc_metadata/metadata_rules/rule.py +2 -3
- edc_metadata/metadata_rules/rule_evaluator.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 +7 -4
- edc_metadata/model_mixins/updates/updates_requisition_metadata_model_mixin.py +5 -2
- 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/models/signals.py +10 -11
- 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/auths.py +18 -13
- 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/auths.py +9 -4
- 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/graded_event_notification.py +2 -2
- edc_notification/notification/model_notification.py +3 -30
- edc_notification/notification/new_model_notification.py +1 -1
- edc_notification/notification/notification.py +12 -12
- edc_notification/notification/updated_model_notification.py +2 -2
- edc_offstudy/auths.py +12 -7
- 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 +7 -3
- 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/auths.py +19 -15
- 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/formulation.py +5 -7
- 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/prescribe/create_prescription.py +3 -3
- edc_pharmacy/utils/allocate_stock.py +2 -3
- edc_pharmacy/utils/confirm_stock.py +3 -4
- edc_pharmacy/utils/confirm_stock_at_site.py +4 -5
- 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/confirmation_at_site_view.py +6 -9
- 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_prn/admin_site.py +5 -0
- edc_prn/prn.py +10 -11
- edc_prn/urls.py +11 -0
- edc_protocol/research_protocol_config.py +2 -3
- edc_protocol_incident/action_items.py +4 -4
- edc_protocol_incident/auths.py +27 -20
- 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/auths.py +6 -1
- 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/auths.py +11 -7
- 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/admin.py +30 -24
- edc_randomization/auths.py +12 -7
- 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/randomizer.py +22 -20
- edc_randomization/utils.py +19 -18
- edc_refusal/auths.py +7 -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 +4 -4
- edc_registration/auths.py +28 -23
- 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 +15 -7
- edc_registration/models/registered_subject.py +28 -27
- 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/get_reference_range_collection.py +2 -3
- edc_reportable/utils/load_data.py +4 -4
- edc_reportable/utils/update_grading_data.py +5 -5
- edc_review_dashboard/auths.py +23 -18
- 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 +6 -6
- edc_screening/auths.py +35 -30
- edc_screening/eligibility.py +1 -1
- edc_screening/gender_evaluator.py +1 -1
- 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 -6
- edc_screening/model_mixins/screening_fields_model_mixin.py +6 -8
- edc_screening/model_mixins/screening_methods_model_mixin.py +1 -1
- edc_screening/screening_eligibility.py +2 -4
- edc_screening/utils.py +9 -9
- edc_search/generate_slug.py +26 -0
- edc_search/model_mixins.py +10 -22
- edc_sites/auths.py +8 -3
- 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/auths.py +27 -22
- 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/apps.py +0 -21
- edc_timepoint/model_mixins.py +22 -20
- edc_transfer/model_mixins.py +4 -4
- edc_transfer/modeladmin_mixins.py +1 -1
- edc_unblinding/auths.py +9 -4
- 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/__init__.py +3 -1
- edc_utils/age.py +10 -16
- edc_utils/show_urls.py +29 -2
- edc_visit_schedule/auths.py +6 -1
- 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/site_visit_schedules.py +2 -2
- 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 +3 -3
- edc_visit_tracking/models/subject_visit.py +1 -1
- edc_vitals/calculators/bmi.py +7 -5
- edc_vitals/utils.py +1 -1
- edc_form_label/models.py +0 -0
- edc_search/constants.py +0 -1
- edc_search/models.py +0 -0
- edc_search/search_slug.py +0 -50
- edc_search/updater.py +0 -30
- edc_search/wsgi.py +0 -7
- {clinicedc-2.0.6.dist-info → clinicedc-2.0.8.dist-info}/licenses/LICENSE +0 -0
|
@@ -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(
|
edc_appointment/auths.py
CHANGED
|
@@ -8,17 +8,21 @@ from edc_auth.site_auths import site_auths
|
|
|
8
8
|
|
|
9
9
|
from .auth_objects import APPOINTMENT, APPOINTMENT_EXPORT, APPOINTMENT_VIEW, codenames
|
|
10
10
|
|
|
11
|
-
site_auths.add_group(*codenames, name=APPOINTMENT_VIEW, view_only=True)
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
def update_site_auths():
|
|
13
|
+
site_auths.add_group(*codenames, name=APPOINTMENT_VIEW, view_only=True)
|
|
14
14
|
|
|
15
|
-
site_auths.add_group(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
site_auths.add_group(*codenames, name=APPOINTMENT)
|
|
16
|
+
|
|
17
|
+
site_auths.add_group(
|
|
18
|
+
"edc_appointment.export_appointment",
|
|
19
|
+
name=APPOINTMENT_EXPORT,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
site_auths.update_role(APPOINTMENT, name=CLINICIAN_ROLE)
|
|
23
|
+
site_auths.update_role(APPOINTMENT, name=NURSE_ROLE)
|
|
24
|
+
site_auths.update_role(APPOINTMENT_VIEW, name=AUDITOR_ROLE)
|
|
25
|
+
site_auths.update_role(APPOINTMENT, name=CLINICIAN_SUPER_ROLE)
|
|
19
26
|
|
|
20
27
|
|
|
21
|
-
|
|
22
|
-
site_auths.update_role(APPOINTMENT, name=NURSE_ROLE)
|
|
23
|
-
site_auths.update_role(APPOINTMENT_VIEW, name=AUDITOR_ROLE)
|
|
24
|
-
site_auths.update_role(APPOINTMENT, name=CLINICIAN_SUPER_ROLE)
|
|
28
|
+
update_site_auths()
|
|
@@ -215,7 +215,7 @@ class AppointmentCreator:
|
|
|
215
215
|
raise CreateAppointmentDateError(
|
|
216
216
|
f"{e} Visit={self.visit!r}. "
|
|
217
217
|
f"Try setting 'best_effort_available_datetime=True' on facility."
|
|
218
|
-
)
|
|
218
|
+
) from e
|
|
219
219
|
else:
|
|
220
220
|
return self.suggested_datetime
|
|
221
221
|
return arw.datetime
|
|
@@ -85,7 +85,7 @@ class AppointmentsCreator:
|
|
|
85
85
|
except FacilityError as e:
|
|
86
86
|
raise CreateAppointmentError(
|
|
87
87
|
f"{e} See {visit!r}. Got facility_name={visit.facility_name}"
|
|
88
|
-
)
|
|
88
|
+
) from e
|
|
89
89
|
appointment = self.update_or_create_appointment(
|
|
90
90
|
visit=visit,
|
|
91
91
|
taken_datetimes=taken_datetimes,
|
|
@@ -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")
|
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
from __future__ import unicode_literals
|
|
4
4
|
|
|
5
5
|
from django.db import migrations, models
|
|
6
|
-
|
|
7
|
-
import edc_utils
|
|
6
|
+
import django.utils.timezone
|
|
8
7
|
|
|
9
8
|
|
|
10
9
|
class Migration(migrations.Migration):
|
|
@@ -16,22 +15,22 @@ class Migration(migrations.Migration):
|
|
|
16
15
|
migrations.AlterField(
|
|
17
16
|
model_name="appointment",
|
|
18
17
|
name="created",
|
|
19
|
-
field=models.DateTimeField(default=
|
|
18
|
+
field=models.DateTimeField(default=django.utils.timezone.now, editable=False),
|
|
20
19
|
),
|
|
21
20
|
migrations.AlterField(
|
|
22
21
|
model_name="appointment",
|
|
23
22
|
name="modified",
|
|
24
|
-
field=models.DateTimeField(default=
|
|
23
|
+
field=models.DateTimeField(default=django.utils.timezone.now, editable=False),
|
|
25
24
|
),
|
|
26
25
|
migrations.AlterField(
|
|
27
26
|
model_name="historicalappointment",
|
|
28
27
|
name="created",
|
|
29
|
-
field=models.DateTimeField(default=
|
|
28
|
+
field=models.DateTimeField(default=django.utils.timezone.now, editable=False),
|
|
30
29
|
),
|
|
31
30
|
migrations.AlterField(
|
|
32
31
|
model_name="historicalappointment",
|
|
33
32
|
name="modified",
|
|
34
|
-
field=models.DateTimeField(default=
|
|
33
|
+
field=models.DateTimeField(default=django.utils.timezone.now, editable=False),
|
|
35
34
|
),
|
|
36
35
|
migrations.AlterUniqueTogether(name="appointment", unique_together=set([])),
|
|
37
36
|
migrations.RemoveField(model_name="appointment", name="consent_version"),
|