clinicedc 2.0.3__py3-none-any.whl → 2.0.5__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.3.dist-info → clinicedc-2.0.5.dist-info}/METADATA +41 -45
- {clinicedc-2.0.3.dist-info → clinicedc-2.0.5.dist-info}/RECORD +478 -478
- edc_action_item/action.py +76 -54
- edc_action_item/action_item_notification.py +1 -3
- edc_action_item/action_with_notification.py +4 -4
- edc_action_item/create_action_item.py +2 -2
- edc_action_item/create_or_update_action_type.py +1 -1
- edc_action_item/data_fixers.py +4 -5
- edc_action_item/delete_action_item.py +0 -1
- edc_action_item/modeladmin_mixins.py +2 -4
- edc_action_item/modelform_mixins/modelform_mixins.py +1 -1
- edc_action_item/models/action_item.py +53 -38
- edc_action_item/models/action_model_mixin.py +17 -17
- edc_action_item/models/action_type.py +33 -13
- edc_action_item/models/reference.py +3 -2
- edc_action_item/site_action_items.py +13 -14
- edc_action_item/stubs.py +9 -9
- edc_action_item/templatetags/action_item_extras.py +2 -2
- edc_action_item/view_utils/action_item_button.py +3 -3
- edc_action_item/view_utils/action_item_popover_list_item.py +4 -4
- edc_adherence/form_validator_mixin.py +1 -1
- edc_adverse_event/action_items/ae_followup_action.py +1 -1
- edc_adverse_event/action_items/ae_initial_action.py +1 -1
- edc_adverse_event/action_items/ae_susar_action.py +1 -1
- edc_adverse_event/action_items/ae_tmg_action.py +1 -1
- edc_adverse_event/action_items/death_report_action.py +1 -2
- edc_adverse_event/action_items/death_report_tmg_action.py +1 -1
- edc_adverse_event/action_items/death_report_tmg_second_action.py +1 -1
- edc_adverse_event/action_items/hospitalization_action.py +1 -1
- edc_adverse_event/form_validator_mixins/death_report_form_validator.py +3 -3
- edc_adverse_event/form_validator_mixins/requires_death_report_form_validator_mixin.py +3 -4
- edc_adverse_event/form_validators/death_report_tmg.py +1 -1
- edc_adverse_event/model_mixins/ae_followup/ae_followup_methods_model_mixin.py +3 -3
- edc_adverse_event/model_mixins/ae_followup/ae_followup_model_mixin.py +3 -3
- edc_adverse_event/model_mixins/ae_initial/ae_initial_fields_model_mixin.py +0 -1
- edc_adverse_event/model_mixins/ae_initial/ae_initial_methods_model_mixin.py +3 -3
- edc_adverse_event/model_mixins/ae_initial/ae_initial_model_mixin.py +3 -3
- edc_adverse_event/model_mixins/ae_special_interest/aesi_methods_model_mixin.py +4 -4
- edc_adverse_event/model_mixins/ae_special_interest/aesi_model_mixin.py +3 -3
- edc_adverse_event/model_mixins/ae_susar/ae_susar_methods_model_mixin.py +4 -4
- edc_adverse_event/model_mixins/ae_susar/ae_susar_model_mixin.py +3 -3
- edc_adverse_event/model_mixins/ae_tmg/ae_tmg_fields_model_mixin.py +4 -5
- edc_adverse_event/model_mixins/ae_tmg/ae_tmg_methods_model_mixin.py +4 -4
- edc_adverse_event/model_mixins/ae_tmg/ae_tmg_model_mixin.py +3 -3
- edc_adverse_event/model_mixins/death_report/death_report_extra_fields_model_mixin.py +2 -3
- edc_adverse_event/model_mixins/death_report/death_report_model_mixin.py +11 -11
- edc_adverse_event/model_mixins/death_report/death_report_tmg_model_mixin.py +9 -11
- edc_adverse_event/model_mixins/death_report/simple_death_report_model_mixin.py +7 -6
- edc_adverse_event/model_mixins/hospitaization/hospitalization_model_mixin.py +0 -1
- edc_adverse_event/modeladmin_mixins/ae_followup_admin_mixin.py +9 -11
- edc_adverse_event/modeladmin_mixins/ae_initial_admin_mixin.py +4 -6
- edc_adverse_event/modeladmin_mixins/modeladmin_mixins.py +1 -1
- edc_adverse_event/modeladmin_mixins/utils.py +4 -4
- edc_adverse_event/models/signals.py +7 -19
- edc_adverse_event/pdf_reports/death_pdf_report.py +8 -9
- edc_adverse_event/templatetags/edc_adverse_event_extras.py +10 -20
- edc_adverse_event/urls.py +7 -3
- edc_adverse_event/utils.py +2 -2
- edc_adverse_event/view_utils/tmg_button.py +4 -4
- edc_appconfig/system_checks.py +1 -1
- edc_appointment/appointment_status_updater.py +14 -15
- edc_appointment/creators/appointment_creator.py +7 -11
- edc_appointment/creators/appointments_creator.py +1 -1
- edc_appointment/creators/unscheduled_appointment_creator.py +12 -13
- edc_appointment/form_validator_mixins/next_appointment_crf_form_validator_mixin.py +1 -3
- edc_appointment/form_validator_mixins/window_period_form_validator_mixin.py +7 -6
- edc_appointment/form_validators/appointment_form_validator.py +2 -4
- edc_appointment/form_validators/utils.py +4 -4
- edc_appointment/managers.py +4 -4
- edc_appointment/model_mixins/appointment_methods_model_mixin.py +2 -2
- edc_appointment/model_mixins/appointment_model_mixin.py +5 -5
- edc_appointment/model_mixins/window_period_model_mixin.py +1 -1
- edc_appointment/models/appointment.py +1 -1
- edc_appointment/skip_appointments.py +5 -6
- edc_appointment/stubs.py +12 -12
- edc_appointment/utils.py +41 -47
- edc_appointment/view_utils/appointment_button.py +3 -5
- edc_auth/admin/role_admin.py +5 -7
- edc_auth/auth_objects/default_roles.py +1 -3
- edc_auth/auth_updater/auth_updater.py +5 -7
- edc_auth/auth_updater/group_updater.py +8 -8
- edc_auth/auth_updater/role_updater.py +1 -2
- edc_auth/get_app_codenames.py +1 -3
- edc_auth/import_users.py +19 -19
- edc_auth/models/role.py +4 -3
- edc_auth/password_setter.py +6 -7
- edc_auth/send_new_credentials_to_user.py +2 -3
- edc_auth/site_auths.py +3 -3
- edc_consent/actions.py +4 -5
- edc_consent/consent_definition.py +8 -11
- edc_consent/consent_definition_extension.py +3 -3
- edc_consent/form_validators/__init__.py +1 -1
- edc_consent/model_mixins/__init__.py +2 -2
- edc_consent/model_mixins/consent_version_model_mixin.py +1 -1
- edc_consent/modeladmin_mixins/consent_model_admin_mixin.py +1 -2
- edc_consent/modelform_mixins/consent_modelform_mixin/consent_modelform_validation_mixin.py +3 -5
- edc_consent/site_consents.py +10 -15
- edc_consent/stubs.py +2 -2
- edc_consent/utils.py +1 -1
- edc_constants/utils.py +2 -4
- edc_crf/crf_form_validator_mixins.py +2 -2
- edc_crf/model_mixins/crf_no_manager_model_mixin.py +2 -2
- edc_crf/model_mixins/crf_status_model_mixin.py +1 -1
- edc_crf/models/crf_status.py +10 -12
- edc_crf/update_crf_status_command.py +1 -3
- edc_dashboard/management/commands/update_search_slugs.py +8 -11
- edc_dashboard/templatetags/edc_dashboard_extras.py +1 -1
- edc_dashboard/url_config.py +3 -3
- edc_dashboard/utils.py +3 -4
- edc_dashboard/views/dashboard_view.py +1 -1
- edc_data_manager/models/data_dictionary.py +1 -2
- edc_data_manager/models/data_query.py +3 -3
- edc_data_manager/models/query_rule.py +2 -2
- edc_data_manager/tasks.py +0 -2
- edc_device/device.py +1 -1
- edc_device/view_mixins.py +1 -1
- edc_document_status/fieldsets.py +1 -3
- edc_document_status/model_mixins.py +2 -2
- edc_document_status/modeladmin_mixins.py +1 -4
- edc_egfr/admin/egfr_drop_notification_admin_mixin.py +5 -7
- edc_egfr/egfr.py +6 -7
- edc_egfr/get_drop_notification_model.py +1 -1
- edc_egfr/model_mixins/egfr_drop_notification_model_mixin.py +1 -1
- edc_export/archive_exporter.py +26 -27
- edc_export/exportables.py +2 -3
- edc_export/management/commands/import_receipts.py +6 -6
- edc_export/model_exporter/file_history_updater.py +1 -1
- edc_export/model_exporter/model_exporter.py +1 -1
- edc_export/model_exporter/value_getter.py +6 -6
- edc_export/model_mixins/notification_model_mixin.py +4 -4
- edc_export/models/data_request.py +3 -3
- edc_export/models/data_request_history.py +2 -2
- edc_export/models/export_receipt.py +1 -1
- edc_export/models/file_history.py +5 -5
- edc_export/models/plan.py +4 -4
- edc_export/models/upload_export_receipt_file.py +2 -2
- edc_export/utils.py +1 -1
- edc_facility/facility.py +6 -6
- edc_facility/holidays.py +2 -5
- edc_facility/import_holidays.py +6 -6
- edc_facility/model_mixins.py +1 -1
- edc_facility/models/holiday.py +1 -1
- edc_facility/utils.py +3 -3
- edc_fieldsets/fieldsets.py +1 -1
- edc_form_describer/forms_reference.py +5 -8
- edc_form_describer/make_forms_reference.py +1 -1
- edc_form_describer/management/commands/make_forms_reference.py +1 -1
- edc_form_label/custom_label_condition.py +1 -1
- edc_form_label/form_label.py +2 -2
- edc_form_runners/exceptions.py +1 -1
- edc_form_runners/models/issue.py +3 -2
- edc_form_runners/site.py +2 -2
- edc_form_runners/templatetags/form_runners_extras.py +1 -1
- edc_form_runners/utils.py +5 -5
- edc_form_validators/applicable_field_validator.py +32 -32
- edc_form_validators/base_form_validator.py +1 -1
- edc_form_validators/extra_mixins/study_day_form_validator.py +1 -1
- edc_form_validators/many_to_many_field_validator.py +38 -43
- edc_form_validators/other_specify_field_validator.py +9 -17
- edc_form_validators/required_field_validator.py +34 -39
- edc_form_validators/test_case_mixin.py +5 -5
- edc_identifier/admin.py +1 -3
- edc_identifier/identifier.py +2 -3
- edc_identifier/model_mixins.py +5 -8
- edc_identifier/research_identifier.py +10 -12
- edc_identifier/short_identifier.py +1 -1
- edc_identifier/simple_identifier.py +22 -22
- edc_identifier/utils.py +1 -1
- edc_lab/admin/fieldsets.py +7 -9
- edc_lab/admin/modeladmin_mixins.py +5 -6
- edc_lab/form_validators/requisition_form_validator_mixin.py +2 -3
- edc_lab/forms/box_form.py +5 -11
- edc_lab/identifiers/aliquot_identifier.py +5 -8
- edc_lab/identifiers/prefix.py +2 -5
- edc_lab/lab/aliquot_creator.py +1 -2
- edc_lab/lab/aliquot_type.py +2 -4
- edc_lab/lab/manifest.py +5 -7
- edc_lab/lab/requisition_panel.py +2 -4
- edc_lab/lab/requisition_panel_group.py +5 -7
- edc_lab/model_mixins/requisition/requisition_model_mixin.py +5 -4
- edc_lab/model_mixins/shipping/manifest_model_mixin.py +6 -6
- edc_lab/model_mixins/shipping/verify_model_mixin.py +4 -3
- edc_lab/models/aliquot.py +1 -1
- edc_lab/models/box.py +2 -2
- edc_lab/models/box_item.py +1 -1
- edc_lab/models/box_type.py +1 -1
- edc_lab/models/manifest/manifest_item.py +1 -1
- edc_lab/pdf_reports/manifest_pdf_report.py +3 -7
- edc_lab/site_labs.py +3 -3
- edc_lab_dashboard/dashboard_templates.py +1 -1
- edc_lab_dashboard/view_mixins/box_view_mixin.py +4 -9
- edc_lab_dashboard/views/action_views/action_view.py +1 -2
- edc_lab_dashboard/views/action_views/manage_manifest_view.py +1 -1
- edc_lab_dashboard/views/action_views/manifest_view.py +9 -11
- edc_lab_dashboard/views/action_views/pack_view.py +11 -14
- edc_lab_results/calculate_missing.py +2 -2
- edc_lab_results/fieldsets.py +6 -6
- edc_lab_results/model_mixin_factories/__init__.py +2 -2
- edc_lab_results/model_mixin_factories/reportable_result_model_mixin_factory.py +7 -9
- edc_lab_results/model_mixin_factories/result_model_mixin_factory.py +7 -9
- edc_lab_results/model_mixins/fbg_model_mixin.py +1 -1
- edc_lab_results/model_mixins/glucose_model_mixin.py +1 -1
- edc_label/admin.py +1 -3
- edc_label/label.py +2 -4
- edc_label/label_template.py +1 -1
- edc_label/subject_label.py +1 -3
- edc_list_data/admin.py +3 -5
- edc_list_data/load_list_data.py +1 -1
- edc_list_data/load_model_data.py +1 -3
- edc_list_data/model_mixins.py +3 -5
- edc_list_data/preload_data.py +2 -4
- edc_list_data/site_list_data.py +6 -7
- edc_listboard/filters/listboard_filter.py +2 -2
- edc_listboard/views/listboard_view.py +1 -3
- edc_locator/models.py +2 -2
- edc_locator/view_mixins/subject_locator_view_mixins.py +2 -2
- edc_ltfu/action_items.py +1 -1
- edc_ltfu/model_mixins.py +0 -2
- edc_ltfu/models.py +4 -4
- edc_metadata/admin/modeladmin_mixins.py +1 -1
- edc_metadata/admin/requisition_metadata.py +2 -4
- edc_metadata/metadata/crf_metadata_getter.py +1 -3
- edc_metadata/metadata/requisition_metadata_getter.py +1 -3
- edc_metadata/metadata_handler.py +2 -2
- edc_metadata/metadata_helper/metadata_helper_mixin.py +2 -3
- edc_metadata/metadata_mixins/source_model_metadata_mixin.py +2 -2
- edc_metadata/metadata_refresher.py +1 -1
- edc_metadata/metadata_rules/crf/crf_rule_group.py +3 -5
- edc_metadata/metadata_rules/logic.py +1 -1
- edc_metadata/metadata_rules/requisition/requisition_rule.py +4 -4
- edc_metadata/metadata_rules/requisition/requisition_rule_group.py +2 -2
- edc_metadata/metadata_rules/rule_evaluator.py +5 -6
- edc_metadata/metadata_rules/rule_group_metaclass.py +2 -3
- edc_metadata/metadata_rules/site.py +6 -7
- edc_metadata/metadata_updater.py +2 -2
- edc_metadata/metadata_wrappers/metadata_wrapper.py +4 -4
- edc_metadata/model_mixins/creates/creates_metadata_model_mixin.py +6 -7
- edc_metadata/model_mixins/updates/updates_crf_metadata_model_mixin.py +2 -2
- edc_metadata/model_mixins/updates/updates_metadata_model_mixin.py +2 -2
- edc_metadata/model_mixins/updates/updates_requisition_metadata_model_mixin.py +2 -2
- edc_metadata/models/crf_metadata.py +27 -29
- edc_metadata/models/crf_metadata_model_mixin.py +1 -1
- edc_metadata/models/requisition_metadata.py +29 -31
- edc_metadata/stubs.py +17 -17
- edc_metadata/utils.py +4 -4
- edc_model/__init__.py +2 -2
- edc_model/models/historical_records.py +2 -2
- edc_model/models/signals.py +1 -1
- edc_model/models/url_model_mixin.py +1 -1
- edc_model/utils.py +0 -2
- edc_model_admin/dashboard/model_admin_dashboard_mixin.py +1 -3
- edc_model_admin/history/model_admin_simple_history.py +7 -9
- edc_model_admin/mixins/base_model_admin_redirect_mixin.py +4 -6
- edc_model_admin/mixins/model_admin_limit_to_selected_foreignkey.py +2 -2
- edc_model_admin/mixins/model_admin_model_redirect_mixin.py +2 -10
- edc_model_admin/mixins/model_admin_next_url_redirect_mixin.py +8 -9
- edc_model_admin/utils.py +6 -9
- edc_model_form/mixins/__init__.py +1 -1
- edc_model_form/mixins/base_model_form_mixin.py +1 -1
- edc_model_to_dataframe/model_to_dataframe.py +2 -4
- edc_navbar/site_navbars.py +2 -2
- edc_navbar/system_checks.py +1 -1
- edc_notification/mailing_list_manager.py +5 -8
- edc_notification/management/commands/list_recipients_by_notification.py +1 -1
- edc_notification/models/__init__.py +4 -2
- edc_notification/notification/graded_event_notification.py +2 -4
- edc_notification/notification/model_notification.py +1 -3
- edc_notification/notification/notification.py +14 -17
- edc_notification/site_notifications.py +7 -7
- edc_notification/stubs.py +6 -6
- edc_notification/update_mailing_lists_in_m2m.py +2 -2
- edc_offstudy/action_items.py +2 -2
- edc_offstudy/model_mixins/offstudy_model_mixin.py +1 -1
- edc_offstudy/models.py +1 -1
- edc_pdf_reports/crf_pdf_report.py +2 -2
- edc_pdf_reports/model_mixins.py +2 -2
- edc_pdf_reports/report.py +4 -5
- edc_pdf_reports/utils.py +1 -1
- edc_pdutils/dataframes/get_subject_consent.py +1 -3
- edc_pdutils/df_exporters/csv_exporter.py +5 -7
- edc_pdutils/df_exporters/tables_exporter.py +2 -2
- edc_pdutils/df_handlers/crf_df_handler.py +1 -2
- edc_pdutils/dialects/crf_dialect.py +3 -3
- edc_pdutils/management/commands/export_models.py +6 -7
- edc_pdutils/site_values_mappings.py +2 -2
- edc_pdutils/utils/datetime_to_date.py +1 -2
- edc_pdutils/utils/refresh_model_from_dataframe.py +1 -3
- edc_pdutils/utils/table_names.py +2 -4
- edc_pdutils/utils/undash.py +1 -1
- edc_pharmacy/admin/medication/assignment_admin.py +2 -4
- edc_pharmacy/admin/medication/dosage_guideline_admin.py +2 -4
- edc_pharmacy/admin/medication/formulation_admin.py +3 -5
- edc_pharmacy/admin/medication/medication_admin.py +3 -5
- edc_pharmacy/admin/prescription/rx_refill_admin.py +7 -9
- edc_pharmacy/admin/stock/lot_admin.py +5 -7
- edc_pharmacy/admin/stock/order_admin.py +2 -2
- edc_pharmacy/admin/stock/order_item_admin.py +6 -6
- edc_pharmacy/admin/stock/receive_admin.py +1 -1
- edc_pharmacy/admin/stock/receive_item_admin.py +2 -2
- edc_pharmacy/admin/stock/stock_request_admin.py +4 -6
- edc_pharmacy/dosage_calculator.py +4 -4
- edc_pharmacy/form_validators/crf/study_medication_form_validator.py +8 -8
- edc_pharmacy/forms/stock/stock_request_form.py +2 -4
- edc_pharmacy/model_mixins/study_medication_crf_model_mixin.py +2 -2
- edc_pharmacy/models/medication/formulation.py +3 -4
- edc_pharmacy/models/medication/medication.py +1 -2
- edc_pharmacy/models/prescription/rx.py +2 -2
- edc_pharmacy/models/prescription/rx_refill.py +7 -9
- edc_pharmacy/models/reports/stock_availability.py +3 -4
- edc_pharmacy/models/stock/confirmation_at_site.py +1 -3
- edc_pharmacy/models/stock/order.py +1 -2
- edc_pharmacy/models/stock/receive.py +3 -4
- edc_pharmacy/models/stock/receive_item.py +2 -3
- edc_pharmacy/models/stock/stock.py +1 -2
- edc_pharmacy/models/stock/stock_adjustment.py +1 -2
- edc_pharmacy/models/stock/stock_request.py +4 -5
- edc_pharmacy/models/storage/box.py +1 -1
- edc_pharmacy/models/storage/items/container_model_mixin.py +1 -1
- edc_pharmacy/models/storage/room.py +1 -1
- edc_pharmacy/models/storage/shelf.py +1 -1
- edc_pharmacy/models/storage/utils.py +15 -16
- edc_pharmacy/prescribe/create_prescription.py +5 -5
- edc_pharmacy/refill/refill_creator.py +1 -1
- edc_pharmacy/sample_usb_printing/usb_printing.py +1 -1
- edc_pharmacy/utils/__init__.py +1 -1
- edc_pharmacy/utils/confirm_stock.py +3 -3
- edc_pharmacy/utils/confirm_stock_at_site.py +9 -8
- edc_pharmacy/utils/dispense.py +5 -8
- edc_pharmacy/utils/format_qty.py +3 -3
- edc_pharmacy/utils/get_codenames.py +1 -1
- edc_pharmacy/utils/miscellaneous.py +1 -1
- edc_pharmacy/utils/process_repack_request.py +18 -19
- edc_pharmacy/utils/process_repack_request_queryset.py +0 -2
- edc_pharmacy/utils/stock_request/bulk_create_stock_request_items.py +2 -3
- edc_pharmacy/views/add_to_storage_bin_view.py +1 -1
- edc_pharmacy/views/allocate_to_subject_view.py +2 -6
- edc_pharmacy/views/confirm_stock_from_instance_view.py +4 -4
- edc_pharmacy/views/confirm_stock_from_queryset_view.py +1 -5
- edc_pharmacy/views/confirmation_at_site_view.py +2 -3
- edc_pharmacy/views/dispense_view.py +1 -1
- edc_pharmacy/views/move_to_storage_bin_view.py +2 -3
- edc_pharmacy/views/print_labels_view.py +30 -31
- edc_pharmacy/views/transfer_stock_view.py +1 -1
- edc_prn/prn.py +1 -1
- edc_prn/site_prn_forms.py +1 -2
- edc_protocol_incident/action_items.py +2 -2
- edc_protocol_incident/model_mixins/protocol_deviation_violation_model_mixin.py +3 -3
- edc_protocol_incident/model_mixins/protocol_incident_model_mixin.py +3 -5
- edc_protocol_incident/modeladmin_mixins.py +3 -5
- edc_protocol_incident/models/protocol_deviation_violation.py +5 -5
- edc_protocol_incident/models/protocol_incident.py +5 -5
- edc_pylabels/site_label_configs.py +5 -5
- edc_qareports/model_mixins/qa_report_model_mixin.py +4 -2
- edc_qareports/models/qa_reports_log.py +1 -2
- edc_qareports/utils.py +1 -2
- edc_randomization/admin.py +3 -5
- edc_randomization/auth_objects.py +2 -3
- edc_randomization/blinding.py +1 -1
- edc_randomization/constants.py +2 -4
- edc_randomization/model_mixins.py +3 -3
- edc_randomization/randomization_list_importer.py +13 -14
- edc_randomization/randomization_list_verifier.py +11 -13
- edc_randomization/randomizer.py +2 -2
- edc_randomization/system_checks.py +1 -2
- edc_randomization/utils.py +5 -5
- edc_refusal/admin.py +1 -1
- edc_refusal/model_mixins.py +1 -1
- edc_refusal/utils.py +1 -1
- edc_registration/model_mixins/updates_or_creates_registered_subject_model_mixin.py +2 -2
- edc_registration/modeladmin_mixins.py +4 -7
- edc_registration/models/registered_subject.py +7 -9
- edc_registration/utils.py +3 -4
- edc_reportable/data/grading_data/daids_july_2017.py +3 -3
- edc_reportable/evaluator.py +5 -5
- edc_reportable/formula.py +1 -1
- edc_reportable/reference_range_evaluator.py +3 -3
- edc_reportable/utils/convert_units.py +10 -12
- edc_reportable/utils/grading_data_model_cls.py +2 -2
- edc_reportable/utils/grading_exception_model_cls.py +2 -2
- edc_reportable/utils/molecular_weight_model_cls.py +2 -2
- edc_reportable/utils/normal_data_model_cls.py +2 -2
- edc_reportable/utils/reference_range_colllection_model_cls.py +2 -2
- edc_screening/age_evaluator.py +2 -4
- edc_screening/eligibility.py +1 -1
- edc_screening/form_validator_mixins.py +2 -2
- edc_screening/model_mixins/screening_methods_model_mixin.py +1 -1
- edc_screening/screening_eligibility.py +1 -1
- edc_screening/utils.py +4 -6
- edc_search/model_mixins.py +1 -1
- edc_search/search_slug.py +1 -3
- edc_search/updater.py +1 -1
- edc_sites/admin/site_model_admin_mixin.py +2 -2
- edc_sites/model_mixins/site_model_mixin.py +1 -2
- edc_sites/modelform_mixins.py +2 -2
- edc_sites/models/__init__.py +1 -1
- edc_sites/models/site_profile.py +4 -4
- edc_sites/site.py +24 -32
- edc_sites/system_checks.py +1 -1
- edc_sites/utils/get_message_text.py +1 -1
- edc_sites/utils/valid_site_for_subject_or_raise.py +5 -6
- edc_subject_dashboard/requisition_report.py +4 -5
- edc_subject_dashboard/requisition_verifier.py +4 -2
- edc_subject_dashboard/templatetags/edc_subject_dashboard_extras.py +16 -17
- edc_subject_dashboard/view_utils/__init__.py +1 -1
- edc_subject_dashboard/view_utils/crf_button.py +1 -3
- edc_subject_dashboard/view_utils/subject_consent_dashboard_button.py +2 -2
- edc_subject_dashboard/view_utils/subject_consent_listboard_button.py +2 -2
- edc_subject_dashboard/view_utils/timepoint_status_button.py +1 -4
- edc_subject_dashboard/views/requisition_print_actions_view.py +2 -2
- edc_subject_dashboard/views/subject_dashboard_view.py +1 -1
- edc_timepoint/model_mixins.py +2 -2
- edc_transfer/action_items.py +1 -1
- edc_transfer/model_mixins.py +4 -3
- edc_transfer/modeladmin_mixins.py +3 -6
- edc_unblinding/action_items.py +2 -2
- edc_unblinding/models/unblinding_request.py +3 -3
- edc_unblinding/models/unblinding_review.py +3 -3
- edc_utils/__init__.py +6 -5
- edc_utils/age.py +1 -1
- edc_utils/celery.py +3 -8
- edc_utils/get_static_file.py +1 -1
- edc_utils/text.py +5 -6
- edc_view_utils/__init__.py +3 -3
- edc_view_utils/dashboard_model_button.py +4 -4
- edc_view_utils/model_button.py +7 -8
- edc_view_utils/perms.py +3 -3
- edc_visit_schedule/action_items.py +2 -2
- edc_visit_schedule/admin/list_filters.py +11 -9
- edc_visit_schedule/admin/subject_schedule_history_admin.py +13 -15
- edc_visit_schedule/admin/visit_schedule_admin.py +7 -7
- edc_visit_schedule/fieldsets.py +4 -6
- edc_visit_schedule/management/commands/find_invalid_onschedules.py +1 -1
- edc_visit_schedule/model_mixins/off_schedule_model_mixin.py +3 -1
- edc_visit_schedule/model_mixins/on_schedule_model_mixin.py +1 -1
- edc_visit_schedule/modelform_mixins/__init__.py +1 -1
- edc_visit_schedule/modelform_mixins/off_schedule_modelform_mixin.py +1 -2
- edc_visit_schedule/models/subject_schedule_history.py +2 -1
- edc_visit_schedule/models/visit_schedule.py +2 -2
- edc_visit_schedule/schedule/schedule.py +11 -12
- edc_visit_schedule/schedule/visit_collection.py +4 -3
- edc_visit_schedule/schedule/window.py +19 -12
- edc_visit_schedule/site_visit_schedules.py +9 -9
- edc_visit_schedule/subject_schedule.py +6 -7
- edc_visit_schedule/system_checks.py +8 -4
- edc_visit_schedule/view_mixins.py +1 -1
- edc_visit_schedule/visit/crf.py +3 -7
- edc_visit_schedule/visit/requisition.py +2 -2
- edc_visit_schedule/visit/visit.py +6 -7
- edc_visit_schedule/visit/window_period.py +8 -8
- edc_visit_schedule/visit_schedule/schedules_collection.py +2 -5
- edc_visit_tracking/action_items.py +11 -13
- edc_visit_tracking/form_validators/visit_form_validator.py +5 -5
- edc_visit_tracking/model_mixins/base/visit_methods_model_mixin.py +3 -4
- edc_visit_tracking/model_mixins/crfs/visit_tracking_crf_model_mixin.py +2 -2
- edc_visit_tracking/model_mixins/subject_visit_missed_model_mixin.py +2 -3
- edc_visit_tracking/model_mixins/utils.py +1 -1
- edc_visit_tracking/model_mixins/visit_model_mixin/previous_visit_model_mixin.py +2 -2
- edc_visit_tracking/model_mixins/visit_model_mixin/visit_model_mixin.py +3 -3
- edc_visit_tracking/modeladmin_mixins/crf_model_admin_mixin.py +6 -4
- edc_visit_tracking/modeladmin_mixins/visit_model_admin_mixin.py +6 -7
- edc_visit_tracking/modelform_mixins/crf/visit_tracking_crf_modelform_mixin.py +4 -5
- edc_visit_tracking/modelform_mixins/visit_tracking_modelform_mixin.py +3 -4
- edc_visit_tracking/models/subject_visit.py +1 -1
- edc_visit_tracking/models/subject_visit_missed.py +1 -1
- edc_visit_tracking/stubs.py +7 -7
- edc_visit_tracking/typing_stubs.py +11 -11
- edc_visit_tracking/utils.py +5 -5
- edc_visit_tracking/view_utils/related_visit_button.py +5 -5
- edc_vitals/calculators/bmi.py +1 -1
- edc_vitals/form_validators/blood_pressure_form_validator_mixin.py +8 -12
- edc_vitals/form_validators/bmi_form_validator_mixin.py +1 -1
- edc_vitals/form_validators/weight_height_with_bmi_form_validator_mixin.py +5 -2
- edc_vitals/model_mixins/blood_pressure_model_mixin.py +3 -4
- edc_vitals/model_mixins/weight_height_bmi_model_mixin.py +4 -4
- edc_vitals/utils.py +1 -1
- edc_vitals/validators.py +1 -1
- {clinicedc-2.0.3.dist-info → clinicedc-2.0.5.dist-info}/WHEEL +0 -0
- {clinicedc-2.0.3.dist-info → clinicedc-2.0.5.dist-info}/licenses/LICENSE +0 -0
|
@@ -41,13 +41,13 @@ class AeTmgFieldsModelMixin(models.Model):
|
|
|
41
41
|
verbose_name="Date and time of clinical review: ",
|
|
42
42
|
)
|
|
43
43
|
|
|
44
|
-
ae_description = models.TextField(blank=True,
|
|
44
|
+
ae_description = models.TextField(blank=True, verbose_name="Description of AE:")
|
|
45
45
|
|
|
46
46
|
investigator_comments = models.TextField(
|
|
47
|
-
blank=True,
|
|
47
|
+
blank=True, verbose_name="This investigator's comments:"
|
|
48
48
|
)
|
|
49
49
|
|
|
50
|
-
ae_classification = models.CharField(max_length=150, blank=True
|
|
50
|
+
ae_classification = models.CharField(max_length=150, blank=True)
|
|
51
51
|
|
|
52
52
|
ae_classification_other = OtherCharField(max_length=250, blank=True, null=True)
|
|
53
53
|
|
|
@@ -56,11 +56,10 @@ class AeTmgFieldsModelMixin(models.Model):
|
|
|
56
56
|
max_length=15,
|
|
57
57
|
choices=YES_NO,
|
|
58
58
|
blank=False,
|
|
59
|
-
null=True,
|
|
60
59
|
help_text="If No, explain in the narrative below",
|
|
61
60
|
)
|
|
62
61
|
|
|
63
|
-
investigator_narrative = models.TextField(verbose_name="Narrative", blank=True
|
|
62
|
+
investigator_narrative = models.TextField(verbose_name="Narrative", blank=True)
|
|
64
63
|
|
|
65
64
|
investigator_ae_classification_agreed = models.CharField(
|
|
66
65
|
verbose_name=(
|
|
@@ -2,6 +2,9 @@ from django.db import models
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
class AeTmgMethodsModelMixin(models.Model):
|
|
5
|
+
class Meta:
|
|
6
|
+
abstract = True
|
|
7
|
+
|
|
5
8
|
def __str__(self):
|
|
6
9
|
return f"{self.action_identifier[-9:]}"
|
|
7
10
|
|
|
@@ -10,7 +13,7 @@ class AeTmgMethodsModelMixin(models.Model):
|
|
|
10
13
|
super().save(*args, **kwargs)
|
|
11
14
|
|
|
12
15
|
def natural_key(self):
|
|
13
|
-
return (self.action_identifier,)
|
|
16
|
+
return (self.action_identifier,)
|
|
14
17
|
|
|
15
18
|
def get_action_item_reason(self):
|
|
16
19
|
return self.ae_initial.ae_description
|
|
@@ -20,6 +23,3 @@ class AeTmgMethodsModelMixin(models.Model):
|
|
|
20
23
|
fields.append("subject_identifier")
|
|
21
24
|
fields.append("report_status")
|
|
22
25
|
return fields
|
|
23
|
-
|
|
24
|
-
class Meta:
|
|
25
|
-
abstract = True
|
|
@@ -36,7 +36,7 @@ class AeTmgModelMixin(
|
|
|
36
36
|
verbose_name = "AE TMG Report"
|
|
37
37
|
verbose_name_plural = "AE TMG Reports"
|
|
38
38
|
indexes = (
|
|
39
|
-
NonUniqueSubjectIdentifierFieldMixin.Meta.indexes
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
*NonUniqueSubjectIdentifierFieldMixin.Meta.indexes,
|
|
40
|
+
*ActionModelMixin.Meta.indexes,
|
|
41
|
+
models.Index(fields=["subject_identifier", "action_identifier", "site", "id"]),
|
|
42
42
|
)
|
|
@@ -22,14 +22,14 @@ class DeathReportExtraFieldsModelMixin(models.Model):
|
|
|
22
22
|
|
|
23
23
|
hospital_death = models.CharField(
|
|
24
24
|
verbose_name=(
|
|
25
|
-
"Did the participant die in hospital, or die just after
|
|
25
|
+
"Did the participant die in hospital, or die just after visiting a hospital?"
|
|
26
26
|
),
|
|
27
27
|
max_length=50,
|
|
28
28
|
choices=YES_NO,
|
|
29
29
|
)
|
|
30
30
|
|
|
31
31
|
hospital_name = models.CharField(
|
|
32
|
-
verbose_name="Which hospital was this", max_length=50,
|
|
32
|
+
verbose_name="Which hospital was this", max_length=50, blank=True
|
|
33
33
|
)
|
|
34
34
|
|
|
35
35
|
informant = models.CharField(
|
|
@@ -50,7 +50,6 @@ class DeathReportExtraFieldsModelMixin(models.Model):
|
|
|
50
50
|
|
|
51
51
|
comment = models.TextField(
|
|
52
52
|
verbose_name="Comment",
|
|
53
|
-
null=True,
|
|
54
53
|
blank=True,
|
|
55
54
|
help_text="Provide any additional details, if relevant",
|
|
56
55
|
)
|
|
@@ -69,7 +69,6 @@ class DeathReportModelMixin(
|
|
|
69
69
|
choices=YES_NO,
|
|
70
70
|
max_length=5,
|
|
71
71
|
verbose_name="Death as inpatient",
|
|
72
|
-
null=True,
|
|
73
72
|
blank=False,
|
|
74
73
|
)
|
|
75
74
|
|
|
@@ -78,7 +77,7 @@ class DeathReportModelMixin(
|
|
|
78
77
|
on_delete=PROTECT,
|
|
79
78
|
verbose_name="Main cause of death",
|
|
80
79
|
help_text=(
|
|
81
|
-
"Main cause of death in the opinion of the
|
|
80
|
+
"Main cause of death in the opinion of the local study doctor and local PI"
|
|
82
81
|
),
|
|
83
82
|
null=True,
|
|
84
83
|
blank=False,
|
|
@@ -86,7 +85,7 @@ class DeathReportModelMixin(
|
|
|
86
85
|
|
|
87
86
|
cause_of_death_other = OtherCharField(max_length=100, blank=True, null=True)
|
|
88
87
|
|
|
89
|
-
narrative = models.TextField(verbose_name="Narrative", blank=False
|
|
88
|
+
narrative = models.TextField(verbose_name="Narrative", blank=False)
|
|
90
89
|
|
|
91
90
|
objects = ActionIdentifierModelManager()
|
|
92
91
|
|
|
@@ -94,11 +93,6 @@ class DeathReportModelMixin(
|
|
|
94
93
|
|
|
95
94
|
history = HistoricalRecords(inherit=True)
|
|
96
95
|
|
|
97
|
-
def natural_key(self):
|
|
98
|
-
return (self.action_identifier,) # noqa
|
|
99
|
-
|
|
100
|
-
natural_key.dependencies = ["edc_adverse_event.causeofdeath"]
|
|
101
|
-
|
|
102
96
|
class Meta(
|
|
103
97
|
SiteModelMixin.Meta,
|
|
104
98
|
UniqueSubjectIdentifierFieldMixin.Meta,
|
|
@@ -107,6 +101,12 @@ class DeathReportModelMixin(
|
|
|
107
101
|
abstract = True
|
|
108
102
|
verbose_name = "Death Report"
|
|
109
103
|
verbose_name_plural = "Death Reports"
|
|
110
|
-
indexes =
|
|
111
|
-
|
|
112
|
-
|
|
104
|
+
indexes = (
|
|
105
|
+
*ActionNoManagersModelMixin.Meta.indexes,
|
|
106
|
+
models.Index(fields=["subject_identifier", "action_identifier", "site", "id"]),
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
def natural_key(self):
|
|
110
|
+
return (self.action_identifier,)
|
|
111
|
+
|
|
112
|
+
natural_key.dependencies = ("edc_adverse_event.causeofdeath",)
|
|
@@ -59,7 +59,7 @@ class DeathReportTmgFieldsModelMixin(models.Model):
|
|
|
59
59
|
on_delete=PROTECT,
|
|
60
60
|
verbose_name="Main cause of death",
|
|
61
61
|
help_text=(
|
|
62
|
-
"Main cause of death in the opinion of the
|
|
62
|
+
"Main cause of death in the opinion of the local study doctor and local PI"
|
|
63
63
|
),
|
|
64
64
|
null=True,
|
|
65
65
|
)
|
|
@@ -68,24 +68,25 @@ class DeathReportTmgFieldsModelMixin(models.Model):
|
|
|
68
68
|
verbose_name='If "Other" above, please specify',
|
|
69
69
|
max_length=100,
|
|
70
70
|
blank=True,
|
|
71
|
-
null=True,
|
|
72
71
|
)
|
|
73
72
|
|
|
74
73
|
cause_of_death_agreed = models.CharField(
|
|
75
74
|
verbose_name="Is the cause of death agreed between study doctor and TMG member?",
|
|
76
75
|
max_length=15,
|
|
77
76
|
choices=YES_NO,
|
|
78
|
-
null=True,
|
|
79
77
|
help_text="If No, explain in the narrative below",
|
|
80
78
|
)
|
|
81
79
|
|
|
82
|
-
narrative = models.TextField(verbose_name="Narrative", blank=True
|
|
80
|
+
narrative = models.TextField(verbose_name="Narrative", blank=True)
|
|
83
81
|
|
|
84
82
|
class Meta:
|
|
85
83
|
abstract = True
|
|
86
84
|
|
|
87
85
|
|
|
88
86
|
class DeathReportTmgMethodsModelMixin(models.Model):
|
|
87
|
+
class Meta:
|
|
88
|
+
abstract = True
|
|
89
|
+
|
|
89
90
|
def __str__(self):
|
|
90
91
|
return str(self.death_report)
|
|
91
92
|
|
|
@@ -94,13 +95,10 @@ class DeathReportTmgMethodsModelMixin(models.Model):
|
|
|
94
95
|
super().save(*args, **kwargs)
|
|
95
96
|
|
|
96
97
|
def natural_key(self):
|
|
97
|
-
return (self.action_identifier,)
|
|
98
|
+
return (self.action_identifier,)
|
|
98
99
|
|
|
99
100
|
natural_key.dependencies = ["edc_adverse_event.causeofdeath"]
|
|
100
101
|
|
|
101
|
-
class Meta:
|
|
102
|
-
abstract = True
|
|
103
|
-
|
|
104
102
|
|
|
105
103
|
class DeathReportTmgModelMixin(
|
|
106
104
|
SiteModelMixin,
|
|
@@ -126,7 +124,7 @@ class DeathReportTmgModelMixin(
|
|
|
126
124
|
verbose_name = "Death Report TMG (1st)"
|
|
127
125
|
verbose_name_plural = "Death Report TMG (1st)"
|
|
128
126
|
indexes = (
|
|
129
|
-
NonUniqueSubjectIdentifierFieldMixin.Meta.indexes
|
|
130
|
-
|
|
131
|
-
|
|
127
|
+
*NonUniqueSubjectIdentifierFieldMixin.Meta.indexes,
|
|
128
|
+
*ActionModelMixin.Meta.indexes,
|
|
129
|
+
models.Index(fields=["subject_identifier", "action_identifier", "site", "id"]),
|
|
132
130
|
)
|
|
@@ -50,13 +50,14 @@ class SimpleDeathReportModelMixin(
|
|
|
50
50
|
|
|
51
51
|
on_site = ActionIdentifierSiteManager()
|
|
52
52
|
|
|
53
|
-
def natural_key(self):
|
|
54
|
-
return (self.action_identifier,)
|
|
55
|
-
|
|
56
53
|
class Meta(ActionModelMixin.Meta):
|
|
57
54
|
abstract = True
|
|
58
55
|
verbose_name = "Death Report"
|
|
59
56
|
verbose_name_plural = "Death Reports"
|
|
60
|
-
indexes =
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
indexes = (
|
|
58
|
+
*ActionModelMixin.Meta.indexes,
|
|
59
|
+
models.Index(fields=["subject_identifier", "action_identifier", "site", "id"]),
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
def natural_key(self):
|
|
63
|
+
return (self.action_identifier,)
|
|
@@ -45,7 +45,7 @@ class AeFollowupModelAdminMixin(
|
|
|
45
45
|
audit_fieldset_tuple,
|
|
46
46
|
)
|
|
47
47
|
|
|
48
|
-
radio_fields = {
|
|
48
|
+
radio_fields = { # noqa: RUF012
|
|
49
49
|
"outcome": admin.VERTICAL,
|
|
50
50
|
"followup": admin.VERTICAL,
|
|
51
51
|
"ae_grade": admin.VERTICAL,
|
|
@@ -54,14 +54,12 @@ class AeFollowupModelAdminMixin(
|
|
|
54
54
|
def get_search_fields(self, request) -> tuple[str, ...]:
|
|
55
55
|
search_fields = super().get_search_fields(request)
|
|
56
56
|
return tuple(
|
|
57
|
-
|
|
58
|
-
search_fields
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
)
|
|
64
|
-
)
|
|
57
|
+
{
|
|
58
|
+
*search_fields,
|
|
59
|
+
"action_identifier",
|
|
60
|
+
"ae_initial__subject_identifier",
|
|
61
|
+
"ae_initial__action_identifier",
|
|
62
|
+
}
|
|
65
63
|
)
|
|
66
64
|
|
|
67
65
|
def get_list_display(self, request) -> tuple[str, ...]:
|
|
@@ -72,7 +70,7 @@ class AeFollowupModelAdminMixin(
|
|
|
72
70
|
"description_column",
|
|
73
71
|
"documents_column",
|
|
74
72
|
)
|
|
75
|
-
return
|
|
73
|
+
return tuple({*list_display, *custom_fields})
|
|
76
74
|
|
|
77
75
|
def get_list_filter(self, request) -> tuple[str, ...]:
|
|
78
76
|
list_filter = super().get_list_filter(request)
|
|
@@ -83,7 +81,7 @@ class AeFollowupModelAdminMixin(
|
|
|
83
81
|
"outcome",
|
|
84
82
|
"report_datetime",
|
|
85
83
|
)
|
|
86
|
-
return
|
|
84
|
+
return tuple({*list_filter, *custom_fields})
|
|
87
85
|
|
|
88
86
|
@display(description="Description", ordering="-report_datetime")
|
|
89
87
|
def description_column(self, obj):
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Tuple
|
|
2
|
-
|
|
3
1
|
from django.contrib import admin
|
|
4
2
|
from django.contrib.admin import display
|
|
5
3
|
from django.template.loader import render_to_string
|
|
@@ -90,8 +88,8 @@ class AeInitialModelAdminMixin(
|
|
|
90
88
|
additional_instructions = format_html( # nosec B308, B703
|
|
91
89
|
"Complete the initial AE report and forward to the TMG. "
|
|
92
90
|
'Email to <a href="mailto:{}">{}</a>',
|
|
93
|
-
mark_safe(email_contact), #
|
|
94
|
-
mark_safe(email_contact), #
|
|
91
|
+
mark_safe(email_contact), # noqa: S308
|
|
92
|
+
mark_safe(email_contact), # noqa: S308
|
|
95
93
|
)
|
|
96
94
|
|
|
97
95
|
fieldsets = (
|
|
@@ -114,7 +112,7 @@ class AeInitialModelAdminMixin(
|
|
|
114
112
|
"ae_classification_other",
|
|
115
113
|
)
|
|
116
114
|
|
|
117
|
-
def get_list_display(self, request) ->
|
|
115
|
+
def get_list_display(self, request) -> tuple[str, ...]:
|
|
118
116
|
list_display = super().get_list_display(request)
|
|
119
117
|
custom_fields = (
|
|
120
118
|
"subject_identifier_column",
|
|
@@ -125,7 +123,7 @@ class AeInitialModelAdminMixin(
|
|
|
125
123
|
)
|
|
126
124
|
return custom_fields + tuple(f for f in list_display if f not in custom_fields)
|
|
127
125
|
|
|
128
|
-
def get_list_filter(self, request) ->
|
|
126
|
+
def get_list_filter(self, request) -> tuple[str, ...]:
|
|
129
127
|
list_filter = super().get_list_filter(request)
|
|
130
128
|
custom_fields = (
|
|
131
129
|
AeAwarenessListFilter,
|
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
4
|
from datetime import date, datetime
|
|
5
|
-
from typing import TYPE_CHECKING
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
6
|
|
|
7
7
|
from django.conf import settings
|
|
8
8
|
from django.urls import reverse
|
|
@@ -15,11 +15,11 @@ if TYPE_CHECKING:
|
|
|
15
15
|
|
|
16
16
|
from .modeladmin_mixins import AdverseEventModelAdminMixin
|
|
17
17
|
|
|
18
|
-
class ModelAdmin(AdverseEventModelAdminMixin, admin.ModelAdmin): ...
|
|
18
|
+
class ModelAdmin(AdverseEventModelAdminMixin, admin.ModelAdmin): ...
|
|
19
19
|
|
|
20
20
|
class Model(BaseUuidModel):
|
|
21
21
|
report_datetime: datetime
|
|
22
|
-
...
|
|
22
|
+
...
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
@dataclass(order=True)
|
|
@@ -34,7 +34,7 @@ class ColumnItem:
|
|
|
34
34
|
date_field: str | None = field(default="report_datetime", compare=False)
|
|
35
35
|
verbose_name: str = field(init=False, repr=False, compare=False)
|
|
36
36
|
formatted_date: str = field(init=False, repr=False, compare=False)
|
|
37
|
-
model_cls:
|
|
37
|
+
model_cls: type[Model] = field(init=False, repr=False, compare=False)
|
|
38
38
|
date_value: date = field(init=False, repr=False, compare=True)
|
|
39
39
|
|
|
40
40
|
def __post_init__(self):
|
|
@@ -12,14 +12,8 @@ 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(
|
|
16
|
-
|
|
17
|
-
):
|
|
18
|
-
try:
|
|
19
|
-
instance.userprofile
|
|
20
|
-
except AttributeError:
|
|
21
|
-
pass
|
|
22
|
-
else:
|
|
15
|
+
def update_ae_notifications_for_tmg_group(action, instance, **kwargs): # noqa: ARG001
|
|
16
|
+
if getattr(instance, "userprofile", None):
|
|
23
17
|
try:
|
|
24
18
|
tmg_ae_notification = Notification.objects.get(name=AE_TMG_ACTION)
|
|
25
19
|
except ObjectDoesNotExist:
|
|
@@ -35,7 +29,7 @@ def update_ae_notifications_for_tmg_group(
|
|
|
35
29
|
|
|
36
30
|
|
|
37
31
|
@receiver(post_save, weak=False, dispatch_uid="update_ae_initial_for_susar")
|
|
38
|
-
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): # noqa: ARG001
|
|
39
33
|
if not raw and not update_fields:
|
|
40
34
|
try:
|
|
41
35
|
ae_susar_model_cls = get_ae_model("AeSusar")
|
|
@@ -61,7 +55,7 @@ def update_ae_initial_for_susar(sender, instance, raw, update_fields, **kwargs):
|
|
|
61
55
|
weak=False,
|
|
62
56
|
dispatch_uid="update_ae_initial_susar_reported",
|
|
63
57
|
)
|
|
64
|
-
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): # noqa: ARG001
|
|
65
59
|
if not raw and not update_fields:
|
|
66
60
|
try:
|
|
67
61
|
ae_initial_model_cls = get_ae_model("AeInitial")
|
|
@@ -83,7 +77,7 @@ def update_ae_initial_susar_reported(sender, instance, raw, update_fields, **kwa
|
|
|
83
77
|
|
|
84
78
|
|
|
85
79
|
@receiver(post_delete, weak=False, dispatch_uid="post_delete_ae_susar")
|
|
86
|
-
def post_delete_ae_susar(instance, **kwargs):
|
|
80
|
+
def post_delete_ae_susar(instance, **kwargs): # noqa: ARG001
|
|
87
81
|
try:
|
|
88
82
|
ae_susar_model_cls = get_ae_model("AeSusar")
|
|
89
83
|
except LookupError:
|
|
@@ -99,14 +93,8 @@ def post_delete_ae_susar(instance, **kwargs):
|
|
|
99
93
|
|
|
100
94
|
|
|
101
95
|
@receiver(m2m_changed, weak=False, dispatch_uid="update_death_notifications_for_tmg_group")
|
|
102
|
-
def update_death_notifications_for_tmg_group(
|
|
103
|
-
|
|
104
|
-
):
|
|
105
|
-
try:
|
|
106
|
-
instance.userprofile
|
|
107
|
-
except AttributeError:
|
|
108
|
-
pass
|
|
109
|
-
else:
|
|
96
|
+
def update_death_notifications_for_tmg_group(action, instance, **kwargs): # noqa: ARG001
|
|
97
|
+
if getattr(instance, "userprofile", None):
|
|
110
98
|
try:
|
|
111
99
|
tmg_death_notification = Notification.objects.get(name=DEATH_REPORT_TMG_ACTION)
|
|
112
100
|
except ObjectDoesNotExist:
|
|
@@ -95,16 +95,15 @@ class DeathPdfReport(CrfPdfReport):
|
|
|
95
95
|
row = ["Main cause of death:"]
|
|
96
96
|
if not self.model_obj.cause_of_death:
|
|
97
97
|
row.append(self.not_reported_text)
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
width=80,
|
|
104
|
-
)
|
|
98
|
+
elif self.cause_of_death == OTHER:
|
|
99
|
+
row.append(
|
|
100
|
+
fill(
|
|
101
|
+
f"{self.cause_of_death}: {self.cause_of_death_other}",
|
|
102
|
+
width=80,
|
|
105
103
|
)
|
|
106
|
-
|
|
107
|
-
|
|
104
|
+
)
|
|
105
|
+
else:
|
|
106
|
+
row.append(fill(self.cause_of_death))
|
|
108
107
|
rows.append(row)
|
|
109
108
|
|
|
110
109
|
t = Table(rows, (4 * cm, 14 * cm))
|
|
@@ -42,15 +42,15 @@ if TYPE_CHECKING:
|
|
|
42
42
|
DeathReportTmgModelMixin,
|
|
43
43
|
)
|
|
44
44
|
|
|
45
|
-
class DeathReportTmgModel(DeathReportTmgModelMixin, BaseUuidModel): ...
|
|
45
|
+
class DeathReportTmgModel(DeathReportTmgModelMixin, BaseUuidModel): ...
|
|
46
46
|
|
|
47
|
-
class DeathReportTmgSecondModel(DeathReportTmgModelMixin, BaseUuidModel): ...
|
|
47
|
+
class DeathReportTmgSecondModel(DeathReportTmgModelMixin, BaseUuidModel): ...
|
|
48
48
|
|
|
49
|
-
class AeInitialModel(AeInitialModelMixin, BaseUuidModel): ...
|
|
49
|
+
class AeInitialModel(AeInitialModelMixin, BaseUuidModel): ...
|
|
50
50
|
|
|
51
|
-
class AeFollowupModel(AeFollowupModelMixin, BaseUuidModel): ...
|
|
51
|
+
class AeFollowupModel(AeFollowupModelMixin, BaseUuidModel): ...
|
|
52
52
|
|
|
53
|
-
class DeathReportModel(DeathReportModelMixin, BaseUuidModel): ...
|
|
53
|
+
class DeathReportModel(DeathReportModelMixin, BaseUuidModel): ...
|
|
54
54
|
|
|
55
55
|
|
|
56
56
|
register = template.Library()
|
|
@@ -89,17 +89,13 @@ def format_ae_description(context, ae_initial, wrap_length):
|
|
|
89
89
|
try:
|
|
90
90
|
context["sae_reason"] = format_html(
|
|
91
91
|
"{}",
|
|
92
|
-
mark_safe(
|
|
93
|
-
wrapx(escape_braces(ae_initial.sae_reason.name), wrap_length)
|
|
94
|
-
), # nosec B703, B308
|
|
92
|
+
mark_safe(wrapx(escape_braces(ae_initial.sae_reason.name), wrap_length)), # nosec B703, B308
|
|
95
93
|
)
|
|
96
94
|
except AttributeError:
|
|
97
95
|
context["sae_reason"] = ""
|
|
98
96
|
context["ae_description"] = format_html(
|
|
99
97
|
"{}",
|
|
100
|
-
mark_safe(
|
|
101
|
-
wrapx(escape_braces(ae_initial.ae_description), wrap_length)
|
|
102
|
-
), # nosec B703, B308
|
|
98
|
+
mark_safe(wrapx(escape_braces(ae_initial.ae_description), wrap_length)), # nosec B703, B308
|
|
103
99
|
)
|
|
104
100
|
return context
|
|
105
101
|
|
|
@@ -124,15 +120,11 @@ def format_ae_followup_description(context, ae_followup, wrap_length):
|
|
|
124
120
|
context["sae_reason"] = ""
|
|
125
121
|
context["relevant_history"] = format_html(
|
|
126
122
|
"{}",
|
|
127
|
-
mark_safe(
|
|
128
|
-
wrapx(escape_braces(ae_followup.relevant_history), wrap_length)
|
|
129
|
-
), # nosec B703, B308
|
|
123
|
+
mark_safe(wrapx(escape_braces(ae_followup.relevant_history), wrap_length)), # nosec B703, B308
|
|
130
124
|
)
|
|
131
125
|
context["ae_description"] = format_html(
|
|
132
126
|
"{}",
|
|
133
|
-
mark_safe(
|
|
134
|
-
wrapx(escape_braces(ae_followup.ae_initial.ae_description), wrap_length)
|
|
135
|
-
), # nosec B703, B308
|
|
127
|
+
mark_safe(wrapx(escape_braces(ae_followup.ae_initial.ae_description), wrap_length)), # nosec B703, B308
|
|
136
128
|
)
|
|
137
129
|
return context
|
|
138
130
|
|
|
@@ -158,9 +150,7 @@ def format_ae_susar_description(context, ae_susar, wrap_length):
|
|
|
158
150
|
)
|
|
159
151
|
context["ae_description"] = format_html(
|
|
160
152
|
"{}",
|
|
161
|
-
mark_safe(
|
|
162
|
-
wrapx(escape_braces(ae_susar.ae_initial.ae_description), wrap_length)
|
|
163
|
-
), # nosec B703, B308
|
|
153
|
+
mark_safe(wrapx(escape_braces(ae_susar.ae_initial.ae_description), wrap_length)), # nosec B703, B308
|
|
164
154
|
)
|
|
165
155
|
return context
|
|
166
156
|
|
edc_adverse_event/urls.py
CHANGED
|
@@ -3,11 +3,15 @@ from django.urls.conf import path
|
|
|
3
3
|
from edc_protocol.research_protocol_config import ResearchProtocolConfig
|
|
4
4
|
|
|
5
5
|
from .admin_site import edc_adverse_event_admin
|
|
6
|
-
from .views import
|
|
6
|
+
from .views import (
|
|
7
|
+
AeHomeView,
|
|
8
|
+
ClosedTmgAeListboardView,
|
|
9
|
+
NewTmgAeListboardView,
|
|
10
|
+
OpenTmgAeListboardView,
|
|
11
|
+
TmgHomeView,
|
|
12
|
+
)
|
|
7
13
|
from .views import DeathListboardView as TmgDeathListboardView
|
|
8
|
-
from .views import NewTmgAeListboardView, OpenTmgAeListboardView
|
|
9
14
|
from .views import SummaryListboardView as TmgSummaryListboardView
|
|
10
|
-
from .views import TmgHomeView
|
|
11
15
|
|
|
12
16
|
app_name = "edc_adverse_event"
|
|
13
17
|
|
edc_adverse_event/utils.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from django import forms
|
|
6
6
|
from django.apps import apps as django_apps
|
|
@@ -71,7 +71,7 @@ def get_hospitalization_model_app_label() -> str:
|
|
|
71
71
|
|
|
72
72
|
def get_ae_model(
|
|
73
73
|
model_name,
|
|
74
|
-
) ->
|
|
74
|
+
) -> type[DeathReportModelMixin] | type[AeInitialModelMixin] | type[AeFollowupModelMixin]:
|
|
75
75
|
return django_apps.get_model(f"{get_adverse_event_app_label()}.{model_name}")
|
|
76
76
|
|
|
77
77
|
|
|
@@ -17,13 +17,13 @@ if TYPE_CHECKING:
|
|
|
17
17
|
)
|
|
18
18
|
from edc_model.models import BaseUuidModel
|
|
19
19
|
|
|
20
|
-
class AeInitialModel(AeInitialModelMixin, BaseUuidModel): ...
|
|
20
|
+
class AeInitialModel(AeInitialModelMixin, BaseUuidModel): ...
|
|
21
21
|
|
|
22
|
-
class AeFollowupModel(AeFollowupModelMixin, BaseUuidModel): ...
|
|
22
|
+
class AeFollowupModel(AeFollowupModelMixin, BaseUuidModel): ...
|
|
23
23
|
|
|
24
|
-
class DeathReportTmgModel(DeathReportTmgModelMixin, BaseUuidModel): ...
|
|
24
|
+
class DeathReportTmgModel(DeathReportTmgModelMixin, BaseUuidModel): ...
|
|
25
25
|
|
|
26
|
-
class DeathReportModel(DeathReportModelMixin, BaseUuidModel): ...
|
|
26
|
+
class DeathReportModel(DeathReportModelMixin, BaseUuidModel): ...
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
@dataclass
|
edc_appconfig/system_checks.py
CHANGED
|
@@ -21,7 +21,7 @@ def check_for_edc_appconfig(app_configs, **kwargs) -> list[CheckMessage]:
|
|
|
21
21
|
id="edc_appconfig.E001",
|
|
22
22
|
)
|
|
23
23
|
)
|
|
24
|
-
if
|
|
24
|
+
if settings.INSTALLED_APPS[-1:][0] != "edc_appconfig.apps.AppConfig":
|
|
25
25
|
errors.append(
|
|
26
26
|
Error(
|
|
27
27
|
"edc_appconfig should be the last app in INSTALLED_APPS. "
|
|
@@ -25,18 +25,17 @@ class AppointmentStatusUpdater:
|
|
|
25
25
|
raise AppointmentStatusUpdaterError(
|
|
26
26
|
f"Not an Appointment model instance. Got {self.appointment._meta.label_lower}."
|
|
27
27
|
)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
update_appt_status(appointment, save=True)
|
|
28
|
+
if not getattr(self.appointment, "id", None):
|
|
29
|
+
raise AppointmentStatusUpdaterError(
|
|
30
|
+
"Appointment instance must exist. Got `id` is None"
|
|
31
|
+
)
|
|
32
|
+
if change_to_in_progress and self.appointment.appt_status != IN_PROGRESS_APPT:
|
|
33
|
+
self.appointment.appt_status = IN_PROGRESS_APPT
|
|
34
|
+
self.appointment.save_base(update_fields=["appt_status"])
|
|
35
|
+
if clear_others_in_progress:
|
|
36
|
+
for appointment in self.appointment.__class__.objects.filter(
|
|
37
|
+
visit_schedule_name=self.appointment.visit_schedule_name,
|
|
38
|
+
schedule_name=self.appointment.schedule_name,
|
|
39
|
+
appt_status=IN_PROGRESS_APPT,
|
|
40
|
+
).exclude(id=self.appointment.id):
|
|
41
|
+
update_appt_status(appointment, save=True)
|