clinicedc 2.0.1__py3-none-any.whl → 2.0.3__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.1.dist-info → clinicedc-2.0.3.dist-info}/METADATA +15 -22
- {clinicedc-2.0.1.dist-info → clinicedc-2.0.3.dist-info}/RECORD +854 -787
- {clinicedc-2.0.1.dist-info → clinicedc-2.0.3.dist-info}/WHEEL +1 -1
- edc_action_item/action.py +10 -30
- edc_action_item/action_with_notification.py +1 -2
- edc_action_item/admin/action_item_admin.py +2 -6
- edc_action_item/admin_site.py +1 -3
- edc_action_item/auths.py +1 -3
- edc_action_item/create_or_update_action_type.py +1 -3
- edc_action_item/data_fixers.py +6 -20
- edc_action_item/forms/action_item_form.py +1 -3
- edc_action_item/management/commands/inspect_action_items.py +3 -9
- edc_action_item/migrations/0001_initial.py +4 -5
- edc_action_item/migrations/0003_auto_20180116_1528.py +2 -1
- edc_action_item/migrations/0006_auto_20180707_1659.py +3 -4
- edc_action_item/migrations/0007_auto_20180707_1715.py +1 -3
- edc_action_item/migrations/0008_auto_20180809_0303.py +2 -1
- edc_action_item/migrations/0014_auto_20181121_1738.py +2 -6
- edc_action_item/migrations/0015_auto_20190114_0250.py +4 -3
- edc_action_item/migrations/0021_auto_20190628_2113.py +1 -3
- edc_action_item/migrations/0022_auto_20190628_2136.py +2 -6
- edc_action_item/migrations/0030_edcpermissions.py +1 -1
- edc_action_item/migrations/0033_alter_actionitem_managers.py +1 -0
- edc_action_item/migrations/0034_alter_actionitem_device_created_and_more.py +13 -37
- edc_action_item/models/action_item.py +2 -6
- edc_action_item/models/action_model_mixin.py +5 -16
- edc_action_item/models/action_type.py +1 -3
- edc_action_item/models/reference.py +1 -2
- edc_action_item/models/signals.py +3 -9
- edc_action_item/site_action_items.py +5 -15
- edc_action_item/templatetags/action_item_extras.py +1 -3
- edc_action_item/view_utils/action_item_button.py +1 -3
- edc_action_item/view_utils/action_item_popover_list_item.py +1 -2
- edc_adherence/migrations/0002_nonadherencereasons_plural_name.py +1 -3
- edc_adherence/model_admin_mixin.py +1 -3
- edc_adverse_event/action_items/ae_followup_action.py +2 -6
- edc_adverse_event/action_items/ae_initial_action.py +3 -7
- edc_adverse_event/auth_objects.py +2 -6
- edc_adverse_event/constants.py +1 -3
- edc_adverse_event/form_validator_mixins/death_report_form_validator.py +1 -3
- edc_adverse_event/form_validator_mixins/requires_death_report_form_validator_mixin.py +2 -7
- edc_adverse_event/form_validators/hospitalization.py +1 -3
- edc_adverse_event/migrations/0003_auto_20191026_2231.py +3 -9
- edc_adverse_event/migrations/0008_auto_20220825_0451.py +1 -1
- edc_adverse_event/migrations/0009_auto_20220907_0157.py +1 -1
- edc_adverse_event/migrations/0010_auto_20220913_2139.py +4 -12
- edc_adverse_event/migrations/0013_alter_aeactionclassification_device_created_and_more.py +11 -31
- edc_adverse_event/model_mixins/ae_followup/ae_followup_fields_model_mixin.py +1 -3
- edc_adverse_event/model_mixins/ae_followup/ae_followup_model_mixin.py +1 -5
- edc_adverse_event/model_mixins/ae_initial/ae_initial_ae_model_mixin.py +1 -3
- edc_adverse_event/model_mixins/ae_initial/ae_initial_fields_model_mixin.py +1 -3
- edc_adverse_event/model_mixins/ae_initial/ae_initial_susar_model_mixin.py +1 -2
- edc_adverse_event/model_mixins/ae_special_interest/aesi_model_mixin.py +1 -5
- edc_adverse_event/model_mixins/ae_susar/ae_susar_model_mixin.py +1 -5
- edc_adverse_event/model_mixins/ae_tmg/ae_tmg_fields_model_mixin.py +2 -6
- edc_adverse_event/model_mixins/ae_tmg/ae_tmg_model_mixin.py +1 -5
- edc_adverse_event/model_mixins/death_report/death_report_extra_fields_model_mixin.py +1 -2
- edc_adverse_event/model_mixins/death_report/death_report_model_mixin.py +2 -5
- edc_adverse_event/model_mixins/death_report/death_report_tmg_model_mixin.py +2 -7
- edc_adverse_event/model_mixins/death_report/simple_death_report_model_mixin.py +1 -3
- edc_adverse_event/modeladmin_mixins/ae_tmg_admin_mixin.py +1 -3
- edc_adverse_event/modeladmin_mixins/death_report_admin_mixin.py +6 -10
- edc_adverse_event/modelform_mixins/ae_tmg_modelform_mixin.py +1 -3
- edc_adverse_event/models/signals.py +3 -9
- edc_adverse_event/pdf_reports/ae_pdf_report.py +6 -18
- edc_adverse_event/pdf_reports/death_pdf_report.py +3 -9
- edc_adverse_event/templatetags/edc_adverse_event_extras.py +5 -15
- edc_adverse_event/utils.py +2 -6
- edc_adverse_event/view_mixins/ae/ae_listboard_view_mixin.py +1 -3
- edc_adverse_event/view_mixins/ae/death_report_listboard_view_mixin.py +1 -3
- edc_adverse_event/view_mixins/tmg/tmg_ae_listboard_view_mixin.py +2 -6
- edc_adverse_event/view_utils/tmg_button.py +2 -6
- edc_adverse_event/views/home_view.py +1 -3
- edc_adverse_event/views/tmg/death_listboard_view.py +1 -3
- edc_adverse_event/views/tmg/home_view.py +2 -6
- edc_adverse_event/views/tmg/summary_listboard_view.py +1 -3
- edc_appointment/admin/appointment_admin.py +1 -3
- edc_appointment/admin/list_filters.py +1 -3
- edc_appointment/admin_site.py +1 -3
- edc_appointment/analytics/dataframes/get_appointment_df.py +2 -6
- edc_appointment/appointment_reason_updater.py +2 -5
- edc_appointment/appointment_status_updater.py +1 -4
- edc_appointment/constants.py +1 -3
- edc_appointment/creators/appointment_creator.py +4 -10
- edc_appointment/creators/unscheduled_appointment_creator.py +3 -7
- edc_appointment/creators/utils.py +4 -0
- edc_appointment/form_validator_mixins/next_appointment_crf_form_validator_mixin.py +3 -10
- edc_appointment/form_validator_mixins/window_period_form_validator_mixin.py +3 -9
- edc_appointment/form_validators/appointment_form_validator.py +11 -37
- edc_appointment/form_validators/next_appointment_crf_form_validator.py +1 -3
- edc_appointment/form_validators/utils.py +1 -3
- edc_appointment/managers.py +2 -6
- edc_appointment/migrations/0002_auto_20161126_1156.py +5 -8
- edc_appointment/migrations/0003_auto_20161127_2226.py +7 -16
- edc_appointment/migrations/0006_auto_20170106_2118.py +2 -1
- edc_appointment/migrations/0008_auto_20171115_1601.py +3 -4
- edc_appointment/migrations/0014_auto_20180116_1411.py +2 -1
- edc_appointment/migrations/0024_auto_20200911_0425.py +1 -1
- edc_appointment/migrations/0034_appointmenttype_alter_appointment_appt_type_and_more.py +2 -4
- edc_appointment/migrations/0036_auto_20230124_1822.py +2 -6
- edc_appointment/migrations/0040_appointment_appt_type_other_and_more.py +1 -0
- edc_appointment/migrations/0042_alter_appointment_device_created_and_more.py +5 -13
- edc_appointment/migrations/0046_infosources.py +1 -3
- edc_appointment/migrations/0047_alter_appointment_options_and_more.py +1 -3
- edc_appointment/model_mixins/appointment_methods_model_mixin.py +1 -5
- edc_appointment/model_mixins/appointment_model_mixin.py +2 -8
- edc_appointment/model_mixins/next_appointment_crf_model_mixin.py +1 -3
- edc_appointment/modeladmin_mixins/next_appointment_crf_modeladmin_mixin.py +1 -3
- edc_appointment/modelform_mixins/next_appointment_crf_modelform_mixins.py +1 -5
- edc_appointment/models/signals.py +5 -17
- edc_appointment/utils.py +11 -33
- edc_appointment/view_mixins/appointment_view_mixin.py +2 -6
- edc_auth/admin/list_filters.py +2 -6
- edc_auth/admin/role_admin.py +1 -3
- edc_auth/admin/user_admin.py +4 -12
- edc_auth/admin/user_profile_admin.py +2 -5
- edc_auth/auth_updater/auth_updater.py +1 -3
- edc_auth/auth_updater/group_updater.py +3 -9
- edc_auth/forms.py +1 -3
- edc_auth/get_app_codenames.py +1 -3
- edc_auth/import_users.py +3 -9
- edc_auth/management/commands/export_users.py +1 -3
- edc_auth/management/commands/reset_password.py +1 -3
- edc_auth/migrations/0001_squashed_0033_alter_userprofile_is_multisite_viewer.py +4 -12
- edc_auth/migrations/0015_auto_20191026_2149.py +1 -3
- edc_auth/migrations/0016_auto_20191026_2153.py +1 -3
- edc_auth/migrations/0025_permissions.py +1 -1
- edc_auth/migrations/0029_alter_edcpermissions_device_created_and_more.py +5 -13
- edc_auth/models/__init__.py +1 -3
- edc_auth/models/signals.py +2 -6
- edc_auth/models/user_profile.py +1 -3
- edc_auth/password_setter.py +1 -3
- edc_auth/system_checks.py +1 -5
- edc_auth/urls_for_accounts.py +1 -3
- edc_auth/utils.py +3 -9
- edc_consent/actions.py +3 -9
- edc_consent/consent_definition.py +2 -6
- edc_consent/consent_definition_extension.py +4 -12
- edc_consent/field_mixins/citizen_fields_mixin.py +2 -4
- edc_consent/field_mixins/identity_fields_mixin.py +1 -2
- edc_consent/field_mixins/personal_fields_mixin.py +8 -3
- edc_consent/field_mixins/site_fields_mixin.py +1 -2
- edc_consent/form_validators/subject_consent_form_validator.py +2 -7
- edc_consent/migrations/0001_initial.py +1 -1
- edc_consent/migrations/0002_alter_edcpermissions_device_created_and_more.py +3 -7
- edc_consent/model_mixins/consent_extension_model_mixin.py +1 -3
- edc_consent/model_mixins/consent_model_mixin.py +3 -9
- edc_consent/modeladmin_mixins/consent_model_admin_mixin.py +7 -17
- edc_consent/modelform_mixins/consent_modelform_mixin/consent_modelform_validation_mixin.py +3 -8
- edc_consent/modelform_mixins/requires_consent_modelform_mixin.py +1 -3
- edc_consent/models/signals.py +2 -6
- edc_consent/site_consents.py +5 -17
- edc_consent/system_checks.py +3 -9
- edc_consent/validators.py +1 -2
- edc_consent/view_mixins/consent_view_mixins.py +3 -5
- edc_crf/crf_form_validator.py +2 -6
- edc_crf/crf_form_validator_mixins.py +2 -6
- edc_crf/migrations/0004_alter_crfstatus_device_created_and_more.py +3 -7
- edc_crf/utils.py +1 -3
- edc_dashboard/management/commands/update_search_slugs.py +1 -3
- edc_dashboard/migrations/0001_initial.py +1 -1
- edc_dashboard/migrations/0003_alter_edcpermissions_device_created_and_more.py +3 -7
- edc_dashboard/templatetags/edc_dashboard_extras.py +2 -6
- edc_dashboard/view_mixins/administration_view_mixin.py +1 -3
- edc_dashboard/view_mixins/edc_view_mixin.py +1 -3
- edc_dashboard/views/administration_view.py +1 -3
- edc_data_manager/action_items.py +1 -3
- edc_data_manager/admin/actions.py +3 -9
- edc_data_manager/admin/data_query_admin.py +4 -12
- edc_data_manager/admin/query_rule_admin.py +4 -13
- edc_data_manager/auths.py +1 -3
- edc_data_manager/forms/data_query.py +2 -6
- edc_data_manager/forms/query_rule.py +1 -3
- edc_data_manager/get_longitudinal_value.py +2 -5
- edc_data_manager/handlers/handlers.py +2 -6
- edc_data_manager/migrations/0001_initial.py +4 -3
- edc_data_manager/migrations/0003_auto_20190806_1749.py +2 -6
- edc_data_manager/migrations/0004_auto_20190806_1750.py +1 -3
- edc_data_manager/migrations/0025_edcpermissions.py +1 -1
- edc_data_manager/migrations/0027_alter_dataquery_dm_user.py +1 -1
- edc_data_manager/migrations/0028_alter_dataquery_options_alter_queryrule_options_and_more.py +2 -1
- edc_data_manager/migrations/0029_alter_dataquery_managers.py +2 -1
- edc_data_manager/migrations/0030_alter_datadictionary_device_created_and_more.py +15 -43
- edc_data_manager/models/model_mixins.py +1 -3
- edc_data_manager/populate_data_dictionary.py +1 -2
- edc_data_manager/post_migrate_signals.py +1 -3
- edc_data_manager/site_data_manager.py +1 -3
- edc_document_status/model_mixins.py +1 -3
- edc_egfr/__init__.py +1 -0
- edc_egfr/admin/__init__.py +1 -0
- edc_egfr/admin/egfr_drop_notification_admin_mixin.py +73 -0
- edc_egfr/apps.py +5 -0
- edc_egfr/calculators/__init__.py +4 -0
- edc_egfr/calculators/base_egrfr.py +56 -0
- edc_egfr/calculators/egfr_ckd_epi.py +68 -0
- edc_egfr/calculators/egfr_cockcroft_gault.py +63 -0
- edc_egfr/calculators/percent_change.py +7 -0
- edc_egfr/constants.py +1 -0
- edc_egfr/egfr.py +237 -0
- edc_egfr/form_validator_mixins/__init__.py +4 -0
- edc_egfr/form_validator_mixins/egfr_form_validator_mixins.py +55 -0
- edc_egfr/get_drop_notification_model.py +10 -0
- edc_egfr/get_egfr_for_subject.py +31 -0
- edc_egfr/model_mixins/__init__.py +2 -0
- edc_egfr/model_mixins/egfr_drop_notification_model_mixin.py +63 -0
- edc_egfr/model_mixins/egfr_model_mixin.py +120 -0
- edc_export/archive_exporter.py +2 -6
- edc_export/exportables.py +2 -6
- edc_export/files_emailer.py +1 -3
- edc_export/management/commands/import_receipts.py +1 -3
- edc_export/managers.py +3 -9
- edc_export/migrations/0001_initial.py +15 -36
- edc_export/migrations/0005_exportdata_importdata.py +1 -3
- edc_export/migrations/0006_auto_20200512_0208.py +2 -6
- edc_export/migrations/0010_auto_20210910_1636.py +2 -6
- edc_export/migrations/0013_edcpermissions.py +1 -1
- edc_export/migrations/0015_alter_datarequest_managers_and_more.py +2 -1
- edc_export/migrations/0016_alter_datarequest_device_created_and_more.py +27 -79
- edc_export/migrations/0017_alter_datarequest_options_and_more.py +2 -6
- edc_export/migrations/0020_remove_datarequesthistory_edc_export__exporte_ba8050_idx_and_more.py +2 -6
- edc_export/model_exporter/model_exporter.py +4 -15
- edc_export/model_exporter/object_history_helpers.py +1 -3
- edc_export/model_exporter/value_getter.py +5 -14
- edc_export/models/signals.py +1 -3
- edc_export/models/upload_export_receipt_file.py +1 -3
- edc_export/utils.py +1 -4
- edc_export/views/export_selected_models_view.py +6 -17
- edc_facility/default_definitions.py +1 -3
- edc_facility/facility.py +4 -14
- edc_facility/import_holidays.py +1 -3
- edc_facility/migrations/0005_healthfacility_healthfacilitytypes_and_more.py +4 -6
- edc_facility/migrations/0006_alter_healthfacility_health_facility_type.py +1 -1
- edc_facility/migrations/0008_alter_healthfacility_device_created_and_more.py +5 -13
- edc_facility/models/holiday.py +1 -3
- edc_facility/utils.py +1 -3
- edc_fieldsets/fieldsets_modeladmin_mixin.py +1 -3
- edc_form_describer/form_describer.py +3 -9
- edc_form_describer/make_forms_reference.py +1 -3
- edc_form_describer/management/commands/make_forms_reference.py +1 -3
- edc_form_runners/admin/issue_admin.py +2 -6
- edc_form_runners/form_runner.py +4 -13
- edc_form_runners/form_runner_by_scr_id.py +1 -3
- edc_form_runners/get_form_runner.py +1 -3
- edc_form_runners/get_form_runner_by_src_id.py +3 -3
- edc_form_runners/management/commands/run_form_runners.py +1 -3
- edc_form_runners/migrations/0001_initial.py +2 -4
- edc_form_runners/run_form_runners.py +1 -3
- edc_form_runners/utils.py +1 -3
- edc_form_validators/applicable_field_validator.py +6 -17
- edc_form_validators/base_form_validator.py +1 -3
- edc_form_validators/date_range_validator.py +4 -12
- edc_form_validators/date_validator.py +3 -9
- edc_form_validators/many_to_many_field_validator.py +1 -3
- edc_form_validators/other_specify_field_validator.py +3 -7
- edc_form_validators/range_field_validator.py +1 -3
- edc_form_validators/required_field_validator.py +5 -18
- edc_glucose/__init__.py +0 -0
- edc_glucose/apps.py +6 -0
- edc_glucose/constants.py +3 -0
- edc_glucose/fieldsets.py +14 -0
- edc_glucose/form_validators/__init__.py +6 -0
- edc_glucose/form_validators/fasting_form_validator.py +12 -0
- edc_glucose/form_validators/fbg_form_validator_mixin.py +32 -0
- edc_glucose/form_validators/fbg_ogtt_form_validator_mixin.py +47 -0
- edc_glucose/form_validators/glucose_form_validator.py +44 -0
- edc_glucose/form_validators/glucose_form_validator_mixin.py +53 -0
- edc_glucose/form_validators/ogtt_form_validator_mixin.py +91 -0
- edc_glucose/list_filters.py +42 -0
- edc_glucose/migrations/__init__.py +0 -0
- edc_glucose/model_mixin_factories/__init__.py +4 -0
- edc_glucose/model_mixin_factories/fasting_model_mixin_factory.py +63 -0
- edc_glucose/model_mixin_factories/fbg_model_mixin_factory.py +48 -0
- edc_glucose/model_mixin_factories/glucose_model_mixin_factory.py +49 -0
- edc_glucose/model_mixin_factories/ogtt_model_mixin_factory.py +71 -0
- edc_glucose/model_mixins/__init__.py +5 -0
- edc_glucose/model_mixins/fasting_model_mixin.py +15 -0
- edc_glucose/model_mixins/fbg_model_mixin.py +10 -0
- edc_glucose/model_mixins/glucose_model_mixin.py +17 -0
- edc_glucose/model_mixins/hba1c_model_mixin.py +42 -0
- edc_glucose/model_mixins/ogtt_model_mixin.py +10 -0
- edc_glucose/models.py +0 -0
- edc_glucose/utils.py +42 -0
- edc_identifier/admin_site.py +1 -3
- edc_identifier/identifier.py +1 -3
- edc_identifier/migrations/0001_initial.py +3 -4
- edc_identifier/migrations/0001_squashed_0018_auto_20180128_1054.py +3 -2
- edc_identifier/migrations/0005_alter_identifiermodel_managers.py +2 -1
- edc_identifier/migrations/0005_historicalidentifierhistory_historicalidentifiertracker_historicalsubjectidentifier.py +4 -5
- edc_identifier/migrations/0006_auto_20161127_2226.py +16 -43
- edc_identifier/migrations/0007_alter_identifiermodel_device_created_and_more.py +3 -7
- edc_identifier/migrations/0007_auto_20161204_2227.py +4 -7
- edc_identifier/migrations/0009_auto_20161221_2323.py +1 -0
- edc_identifier/migrations/0010_auto_20170112_0602.py +2 -1
- edc_identifier/migrations/0012_auto_20171116_1606.py +2 -1
- edc_identifier/migrations/0013_auto_20171230_1316.py +3 -9
- edc_identifier/research_identifier.py +3 -11
- edc_identifier/short_identifier.py +5 -9
- edc_identifier/utils.py +1 -3
- edc_lab/admin/modeladmin_mixins.py +2 -8
- edc_lab/aliquot_types.py +1 -3
- edc_lab/form_validators/requisition_form_validator_mixin.py +1 -3
- edc_lab/forms/box_type_form.py +4 -6
- edc_lab/lab/aliquot_type.py +2 -6
- edc_lab/lab/manifest.py +2 -6
- edc_lab/lab/primary_aliquot.py +1 -3
- edc_lab/lab/requisition_panel.py +1 -3
- edc_lab/lab/requisition_panel_group.py +2 -6
- edc_lab/lab/specimen.py +1 -3
- edc_lab/labels/aliquot_label.py +4 -6
- edc_lab/labels/manifest_label.py +1 -3
- edc_lab/migrations/0001_initial.py +12 -29
- edc_lab/migrations/0002_auto_20170305_1939.py +4 -12
- edc_lab/migrations/0007_auto_20170321_1119.py +2 -6
- edc_lab/migrations/0008_auto_20170921_0719.py +2 -1
- edc_lab/migrations/0010_auto_20171127_1541.py +3 -2
- edc_lab/migrations/0012_auto_20180114_1438.py +2 -1
- edc_lab/migrations/0013_auto_20180117_1438.py +2 -1
- edc_lab/migrations/0022_auto_20211210_1839.py +1 -0
- edc_lab/migrations/0024_alter_manifestitem_managers.py +2 -1
- edc_lab/migrations/0027_alter_aliquot_managers_alter_box_managers_and_more.py +1 -1
- edc_lab/migrations/0028_alter_aliquot_device_created_and_more.py +43 -127
- edc_lab/model_mixins/aliquot/aliquot_label_mixin.py +1 -3
- edc_lab/model_mixins/aliquot/aliquot_model_mixin.py +4 -12
- edc_lab/model_mixins/requisition/requisition_identifier_mixin.py +1 -3
- edc_lab/model_mixins/shipping/manifest_model_mixin.py +1 -3
- edc_lab/models/box_item.py +1 -3
- edc_lab/models/box_type.py +1 -3
- edc_lab/models/manifest/manifest.py +3 -9
- edc_lab/models/manifest/manifest_item.py +1 -3
- edc_lab/models/order.py +1 -3
- edc_lab/models/signals.py +1 -3
- edc_lab/patterns.py +1 -3
- edc_lab/pdf_reports/manifest_pdf_report.py +9 -27
- edc_lab/post_migrate_signals.py +1 -3
- edc_lab/site_labs.py +4 -10
- edc_lab_dashboard/migrations/0001_initial.py +1 -1
- edc_lab_dashboard/migrations/0002_alter_edcpermissions_device_created_and_more.py +3 -7
- edc_lab_dashboard/view_mixins/box_view_mixin.py +1 -3
- edc_lab_dashboard/view_mixins/manifest_view_mixin.py +4 -12
- edc_lab_dashboard/views/action_views/receive_view.py +1 -3
- edc_lab_dashboard/views/action_views/verify_box_item_view.py +1 -3
- edc_lab_dashboard/views/listboard_filters/aliquot_listboard_view_filters.py +2 -6
- edc_lab_dashboard/views/listboard_filters/manifest_listboard_filters.py +1 -3
- edc_lab_dashboard/views/listboard_views/base_box_item_listboard_view.py +1 -3
- edc_lab_dashboard/views/listboard_views/manifest_listboard_view.py +1 -3
- edc_lab_dashboard/views/listboard_views/process_listboard_view.py +2 -6
- edc_lab_dashboard/views/listboard_views/receive_listboard_view.py +2 -6
- edc_lab_dashboard/views/listboard_views/requisition_listboard_view.py +2 -6
- edc_lab_results/action_items.py +1 -3
- edc_lab_results/form_validator_mixins/blood_results_fbg_form_validator_mixin.py +2 -4
- edc_lab_results/form_validator_mixins/blood_results_form_validator_mixin.py +1 -3
- edc_lab_results/get_summary.py +3 -5
- edc_lab_results/model_mixin_factories/__init__.py +10 -0
- edc_lab_results/{model_mixin_factory → model_mixin_factories}/field_attrs.py +8 -8
- edc_lab_results/{model_mixin_factory → model_mixin_factories}/reportable_result_model_mixin_factory.py +2 -0
- edc_lab_results/{model_mixin_factory → model_mixin_factories}/result_model_mixin_factory.py +2 -0
- edc_lab_results/model_mixins/blood_result_model_mixin.py +2 -5
- edc_lab_results/model_mixins/electrolytes_model_mixins.py +1 -1
- edc_lab_results/model_mixins/fbc_model_mixins.py +1 -1
- edc_lab_results/model_mixins/fbg_model_mixin.py +6 -3
- edc_lab_results/model_mixins/glucose_model_mixin.py +2 -2
- edc_lab_results/model_mixins/hba1c_model_mixin.py +2 -28
- edc_lab_results/model_mixins/insulin_model_mixin.py +4 -11
- edc_lab_results/model_mixins/lft_model_mixins.py +1 -1
- edc_lab_results/model_mixins/lipid_model_mixins.py +1 -1
- edc_lab_results/model_mixins/proteinuria_model_mixin.py +1 -1
- edc_lab_results/model_mixins/rft_model_mixins.py +1 -1
- edc_label/apps.py +1 -2
- edc_label/migrations/0001_initial.py +1 -1
- edc_label/migrations/0003_alter_zpllabeltemplates_device_created_and_more.py +3 -7
- edc_label/printer.py +2 -6
- edc_label/printers_mixin.py +1 -3
- edc_label/urls.py +1 -3
- edc_label/view_mixins.py +1 -3
- edc_label/views/print_label_view.py +1 -3
- edc_list_data/model_mixins.py +1 -3
- edc_list_data/preload_data.py +2 -6
- edc_list_data/site_list_data.py +1 -3
- edc_listboard/migrations/0001_initial.py +1 -1
- edc_listboard/migrations/0003_alter_listboard_device_created_and_more.py +3 -7
- edc_listboard/view_mixins/listboard_filter_view_mixin.py +5 -15
- edc_listboard/view_mixins/search_listboard_view_mixin.py +2 -6
- edc_listboard/views/listboard_view.py +2 -6
- edc_listboard/views/screen/screening_listboard_view.py +1 -3
- edc_listboard/views/subject/subject_listboard_view.py +1 -3
- edc_locator/forms/subject_locator_form_validator.py +4 -12
- edc_locator/migrations/0001_initial.py +3 -2
- edc_locator/migrations/0003_auto_20180103_1351.py +2 -1
- edc_locator/migrations/0004_auto_20180106_2148.py +2 -1
- edc_locator/migrations/0007_auto_20180117_1819.py +2 -1
- edc_locator/migrations/0011_auto_20181007_0053.py +1 -1
- edc_locator/migrations/0013_auto_20181007_0054.py +2 -3
- edc_locator/migrations/0014_auto_20181009_0545.py +1 -0
- edc_locator/migrations/0032_alter_subjectlocator_managers.py +1 -1
- edc_locator/migrations/0034_alter_historicalsubjectlocator_device_created_and_more.py +5 -13
- edc_locator/modeladmin_mixins.py +1 -3
- edc_locator/view_mixins/subject_locator_view_mixins.py +1 -3
- edc_ltfu/admin.py +1 -3
- edc_ltfu/forms/ltfu_form.py +1 -3
- edc_ltfu/forms/ltfu_form_validator_mixin.py +1 -2
- edc_ltfu/modelform_mixins.py +3 -8
- edc_metadata/admin/modeladmin_mixins.py +2 -8
- edc_metadata/management/commands/validate_entry_status.py +1 -3
- edc_metadata/metadata/metadata.py +12 -41
- edc_metadata/metadata/metadata_getter.py +2 -9
- edc_metadata/metadata/requisition_metadata_getter.py +1 -3
- edc_metadata/metadata_handler.py +3 -9
- edc_metadata/metadata_helper/metadata_helper_mixin.py +1 -3
- edc_metadata/metadata_mixins/source_model_metadata_mixin.py +3 -9
- edc_metadata/metadata_refresher.py +3 -9
- edc_metadata/metadata_rules/crf/crf_rule_group.py +2 -5
- edc_metadata/metadata_rules/persistant_singleton_mixin.py +3 -3
- edc_metadata/metadata_rules/requisition/requisition_rule_group.py +1 -2
- edc_metadata/metadata_rules/rule_evaluator.py +1 -3
- edc_metadata/metadata_rules/rule_group.py +2 -6
- edc_metadata/metadata_rules/rule_group_meta_options.py +1 -3
- edc_metadata/metadata_updater.py +1 -3
- edc_metadata/metadata_wrappers/metadata_wrapper.py +1 -3
- edc_metadata/migrations/0001_initial.py +2 -1
- edc_metadata/migrations/0002_auto_20161127_2226.py +6 -13
- edc_metadata/migrations/0005_auto_20170112_0602.py +2 -1
- edc_metadata/migrations/0007_auto_20170810_1032.py +2 -1
- edc_metadata/migrations/0009_auto_20180116_1528.py +2 -1
- edc_metadata/migrations/0014_auto_20190707_0002.py +1 -1
- edc_metadata/migrations/0015_auto_20190709_0009.py +3 -5
- edc_metadata/migrations/0021_alter_crfmetadata_managers_and_more.py +1 -1
- edc_metadata/migrations/0023_alter_crfmetadata_device_created_and_more.py +5 -13
- edc_metadata/model_mixins/creates/creates_metadata_model_mixin.py +1 -3
- edc_metadata/model_mixins/updates/updates_metadata_model_mixin.py +1 -3
- edc_metadata/models/crf_metadata_model_mixin.py +2 -6
- edc_metadata/next_form_getter.py +1 -3
- edc_metadata/requisition/requisition_metadata_handler.py +3 -2
- edc_metadata/requisition/requisition_metadata_updater.py +1 -3
- edc_metadata/update_metadata_on_schedule_change.py +7 -14
- edc_model/models/fields/initials_field.py +1 -3
- edc_model/models/signals.py +1 -3
- edc_model/system_checks.py +1 -3
- edc_model/validators/duration.py +1 -3
- edc_model_admin/admin_site.py +1 -3
- edc_model_admin/changelist_buttons/model_admin_changelist_button_mixin.py +4 -12
- edc_model_admin/changelist_buttons/model_admin_changelist_model_button_mixin.py +1 -3
- edc_model_admin/dashboard/model_admin_crf_dashboard_mixin.py +1 -3
- edc_model_admin/dashboard/model_admin_dashboard_mixin.py +1 -3
- edc_model_admin/mixins/base_model_admin_redirect_mixin.py +2 -6
- edc_model_admin/mixins/inlines/limited_admin_inline_mixin.py +1 -3
- edc_model_admin/mixins/model_admin_bypass_default_form_cls_mixin.py +4 -12
- edc_model_admin/mixins/model_admin_form_auto_number_mixin.py +2 -6
- edc_model_admin/mixins/model_admin_form_instructions_mixin.py +2 -6
- edc_model_admin/mixins/model_admin_next_url_redirect_mixin.py +3 -9
- edc_model_admin/mixins/model_admin_protect_pii_mixin.py +1 -3
- edc_model_admin/mixins/model_admin_redirect_all_to_changelist_mixin.py +2 -6
- edc_model_admin/mixins/model_admin_redirect_on_delete_mixin.py +1 -3
- edc_model_admin/templatetags/edc_admin_modify.py +3 -9
- edc_model_fields/fields/initials_field.py +1 -3
- edc_model_form/mixins/inline_model_form_mixin.py +5 -9
- edc_model_to_dataframe/model_to_dataframe.py +15 -46
- edc_navbar/get_default_navbar.py +1 -3
- edc_navbar/migrations/0004_auto_20220825_0451.py +1 -1
- edc_navbar/migrations/0006_alter_edcpermissions_device_created_and_more.py +3 -7
- edc_navbar/navbar.py +1 -3
- edc_navbar/navbar_item.py +1 -3
- edc_navbar/site_navbars.py +2 -6
- edc_navbar/templatetags/edc_navbar_extras.py +1 -3
- edc_notification/admin_site.py +1 -3
- edc_notification/mailing_list_manager.py +5 -15
- edc_notification/migrations/0001_initial.py +2 -1
- edc_notification/migrations/0008_alter_notification_device_created_and_more.py +3 -7
- edc_notification/modeladmin_mixins.py +1 -3
- edc_notification/models/notification.py +1 -3
- edc_notification/models/signals.py +3 -10
- edc_notification/notification/model_notification.py +3 -9
- edc_notification/notification/notification.py +4 -12
- edc_notification/site_notifications.py +5 -14
- edc_offstudy/migrations/0001_initial.py +2 -1
- edc_offstudy/migrations/0002_auto_20180921_0434.py +4 -3
- edc_offstudy/migrations/0008_auto_20191102_0033.py +2 -1
- edc_offstudy/migrations/0015_auto_20220925_0032.py +1 -1
- edc_offstudy/migrations/0016_auto_20220929_1742.py +1 -0
- edc_offstudy/migrations/0018_alter_subjectoffstudy_managers.py +2 -1
- edc_offstudy/migrations/0019_alter_historicalsubjectoffstudy_device_created_and_more.py +5 -13
- edc_offstudy/model_mixins/offstudy_model_mixin.py +3 -3
- edc_offstudy/modelform_mixins/crf/offstudy_crf_modelform_mixin.py +2 -6
- edc_offstudy/templatetags/edc_offstudy_extras.py +2 -6
- edc_offstudy/utils.py +1 -3
- edc_pdf_reports/admin/modeladmin_mixins.py +1 -3
- edc_pdf_reports/crf_pdf_report.py +3 -9
- edc_pdf_reports/flowables/textbox.py +1 -3
- edc_pdf_reports/report.py +6 -18
- edc_pdf_reports/utils.py +1 -3
- edc_pdf_reports/views/pdf_intermediate_view.py +1 -3
- edc_pdf_reports/views/print_pdf_report_view.py +2 -6
- edc_pdutils/actions.py +4 -12
- edc_pdutils/choices.py +1 -4
- edc_pdutils/database.py +1 -3
- edc_pdutils/df_exporters/csv_crf_inline_tables_exporter.py +4 -12
- edc_pdutils/df_exporters/csv_exporter.py +7 -22
- edc_pdutils/df_handlers/crf_df_handler.py +3 -9
- edc_pdutils/df_handlers/df_handler.py +1 -3
- edc_pdutils/df_handlers/registered_subject_df_handler.py +1 -3
- edc_pdutils/management/commands/export_models.py +2 -6
- edc_pdutils/migrations/0001_initial.py +6 -9
- edc_pdutils/site.py +2 -6
- edc_pdutils/site_values_mappings.py +3 -9
- edc_pdutils/tables/aliquot.py +2 -9
- edc_pdutils/tables/consent.py +2 -6
- edc_pdutils/tables/crf.py +4 -12
- edc_pdutils/tables/requisition.py +4 -12
- edc_pdutils/tables/visit.py +1 -3
- edc_pdutils/utils/convert_dates_from_model.py +3 -9
- edc_pdutils/utils/convert_numerics_from_model.py +1 -3
- edc_pdutils/utils/convert_timedelta_from_model.py +1 -3
- edc_pdutils/utils/missing_subject_identifiers.py +1 -3
- edc_pharmacy/admin/actions/confirm_stock.py +2 -6
- edc_pharmacy/admin/actions/delete_order_items.py +1 -3
- edc_pharmacy/admin/actions/delete_receive_items.py +1 -3
- edc_pharmacy/admin/actions/print_stock_report.py +1 -3
- edc_pharmacy/admin/list_filters.py +5 -17
- edc_pharmacy/admin/model_admin_mixin.py +1 -3
- edc_pharmacy/admin/prescription/rx_admin.py +2 -6
- edc_pharmacy/admin/prescription/rx_refill_admin.py +1 -3
- edc_pharmacy/admin/reports/stock_availability_admin.py +1 -5
- edc_pharmacy/admin/stock/allocation_admin.py +5 -15
- edc_pharmacy/admin/stock/allocation_proxy_admin.py +1 -3
- edc_pharmacy/admin/stock/confirmation_admin.py +1 -3
- edc_pharmacy/admin/stock/confirmation_at_site_admin.py +4 -12
- edc_pharmacy/admin/stock/confirmation_at_site_item_admin.py +5 -17
- edc_pharmacy/admin/stock/dispense_admin.py +3 -11
- edc_pharmacy/admin/stock/dispense_item_admin.py +4 -14
- edc_pharmacy/admin/stock/order_admin.py +1 -3
- edc_pharmacy/admin/stock/order_item_admin.py +5 -15
- edc_pharmacy/admin/stock/receive_admin.py +4 -12
- edc_pharmacy/admin/stock/receive_item_admin.py +4 -12
- edc_pharmacy/admin/stock/repack_request_admin.py +2 -6
- edc_pharmacy/admin/stock/stock_adjustment_admin.py +1 -3
- edc_pharmacy/admin/stock/stock_admin.py +8 -24
- edc_pharmacy/admin/stock/stock_proxy_admin.py +1 -5
- edc_pharmacy/admin/stock/stock_request_item_admin.py +5 -15
- edc_pharmacy/admin/stock/stock_transfer_admin.py +4 -12
- edc_pharmacy/admin/stock/stock_transfer_item_admin.py +6 -18
- edc_pharmacy/admin/stock/storage_bin_admin.py +3 -11
- edc_pharmacy/admin/stock/storage_bin_item_admin.py +4 -14
- edc_pharmacy/analytics/dataframes/get_next_scheduled_visit_for_subjects_df.py +3 -9
- edc_pharmacy/analytics/dataframes/in_stock_for_subjects_df.py +2 -6
- edc_pharmacy/analytics/dataframes/stock_for_subjects.py +1 -3
- edc_pharmacy/form_validators/crf/study_medication_form_validator.py +9 -27
- edc_pharmacy/forms/stock/container_form.py +2 -6
- edc_pharmacy/forms/stock/receive_item_form.py +2 -6
- edc_pharmacy/forms/stock/repack_request_form.py +4 -11
- edc_pharmacy/forms/stock/stock_request_form.py +5 -14
- edc_pharmacy/forms/stock/stock_request_item_form.py +1 -3
- edc_pharmacy/labels/draw_bulk_stock_label_code128.py +1 -3
- edc_pharmacy/labels/draw_bulk_stock_label_code39.py +3 -9
- edc_pharmacy/labels/draw_patient_stock_label_code128.py +1 -3
- edc_pharmacy/migrations/0001_initial.py +7 -15
- edc_pharmacy/migrations/0005_alter_rx_managers.py +2 -1
- edc_pharmacy/migrations/0015_auto_20220913_2139.py +9 -22
- edc_pharmacy/migrations/0016_auto_20220929_1742.py +2 -1
- edc_pharmacy/migrations/0018_alter_rxrefill_managers.py +1 -1
- edc_pharmacy/migrations/0020_alter_box_device_created_alter_box_device_modified_and_more.py +71 -211
- edc_pharmacy/migrations/0021_alter_box_options_alter_container_options_and_more.py +1 -1
- edc_pharmacy/migrations/0023_remove_rx_edc_pharmac_modifie_986021_idx_and_more.py +1 -3
- edc_pharmacy/migrations/0024_allocation_assignment_containerunits_dispense_and_more.py +40 -104
- edc_pharmacy/migrations/0031_historicalrepackrequest_task_id_and_more.py +2 -1
- edc_pharmacy/migrations/0033_container_display_name_and_more.py +1 -3
- edc_pharmacy/migrations/0035_container_max_per_subject_and_more.py +2 -6
- edc_pharmacy/migrations/0037_remove_historicalstock_confirmed_at_site_by_and_more.py +2 -6
- edc_pharmacy/migrations/0039_remove_dispense_registered_subject_and_more.py +7 -9
- edc_pharmacy/migrations/0043_stockproxy_alter_historicallot_lot_no_and_more.py +2 -1
- edc_pharmacy/migrations/0049_remove_stocktransferconfirmation_stock_and_more.py +5 -13
- edc_pharmacy/migrations/0050_remove_stocktransferconfirmation2_location_and_more.py +2 -6
- edc_pharmacy/migrations/0051_alter_historicalstocktransferconfirmationitem_options_and_more.py +2 -1
- edc_pharmacy/migrations/0053_alter_location_managers_alter_historicalstock_lot_and_more.py +7 -11
- edc_pharmacy/migrations/0057_scanduplicates.py +3 -4
- edc_pharmacy/migrations/0058_stockrequestproxy_alter_stockproxy_options.py +2 -1
- edc_pharmacy/migrations/0060_alter_container_max_per_subject_and_more.py +8 -14
- edc_pharmacy/migrations/0061_alter_historicalstocktransferconfirmation_options_and_more.py +1 -1
- edc_pharmacy/migrations/0062_auto_20250312_1433.py +2 -6
- edc_pharmacy/migrations/0063_alter_allocation_managers_remove_allocation_site_and_more.py +2 -1
- edc_pharmacy/migrations/0065_allocationproxy.py +2 -1
- edc_pharmacy/migrations/0068_stockout.py +2 -1
- edc_pharmacy/migrations/0076_historicalstockadjustment_stockadjustment.py +5 -8
- edc_pharmacy/migrations/0077_historicalstockadjustment_adjustment_datetime_and_more.py +2 -1
- edc_pharmacy/migrations/0078_alter_historicalstock_qty_and_more.py +2 -1
- edc_pharmacy/migrations/0081_historicalconfirmation_confirmation.py +8 -10
- edc_pharmacy/migrations/0084_confirmationatsiteitem_and_more.py +2 -2
- edc_pharmacy/model_mixins/study_medication_crf_model_mixin.py +3 -9
- edc_pharmacy/models/medication/dosage_guideline.py +1 -3
- edc_pharmacy/models/medication/formulation.py +1 -3
- edc_pharmacy/models/prescription/rx.py +1 -3
- edc_pharmacy/models/prescription/rx_refill.py +2 -6
- edc_pharmacy/models/signals.py +11 -21
- edc_pharmacy/models/stock/allocation.py +3 -9
- edc_pharmacy/models/stock/confirmation.py +1 -3
- edc_pharmacy/models/stock/confirmation_at_site_item.py +1 -3
- edc_pharmacy/models/stock/container.py +1 -3
- edc_pharmacy/models/stock/dispense.py +1 -3
- edc_pharmacy/models/stock/dispense_item.py +1 -3
- edc_pharmacy/models/stock/lot.py +1 -3
- edc_pharmacy/models/stock/order_item.py +2 -6
- edc_pharmacy/models/stock/product.py +2 -6
- edc_pharmacy/models/stock/receive_item.py +4 -12
- edc_pharmacy/models/stock/repack_request.py +1 -3
- edc_pharmacy/models/stock/stock.py +3 -8
- edc_pharmacy/models/stock/stock_request_item.py +4 -4
- edc_pharmacy/models/stock/stock_transfer_item.py +1 -3
- edc_pharmacy/models/stock/supplier.py +1 -3
- edc_pharmacy/models/storage/utils.py +1 -4
- edc_pharmacy/pdf_reports/manifest_pdf_report.py +3 -9
- edc_pharmacy/pdf_reports/stock_pdf_report.py +3 -9
- edc_pharmacy/refill/adjust_previous_end_datetime.py +2 -6
- edc_pharmacy/refill/create_next_refill.py +1 -3
- edc_pharmacy/refill/create_refill.py +1 -3
- edc_pharmacy/refill/refill_creator.py +2 -6
- edc_pharmacy/sample_usb_printing/network_printers.py +1 -3
- edc_pharmacy/settings.py +3 -9
- edc_pharmacy/urls.py +1 -3
- edc_pharmacy/utils/allocate_stock.py +1 -3
- edc_pharmacy/utils/confirm_stock_at_site.py +3 -5
- edc_pharmacy/utils/dispense.py +1 -4
- edc_pharmacy/utils/get_unit_qty_out.py +1 -3
- edc_pharmacy/utils/process_repack_request.py +1 -3
- edc_pharmacy/utils/process_repack_request_queryset.py +1 -3
- edc_pharmacy/utils/stock_request/bulk_create_stock_request_items.py +2 -6
- edc_pharmacy/utils/stock_request/get_instock_and_nostock_data.py +3 -8
- edc_pharmacy/utils/transfer_stock.py +1 -3
- edc_pharmacy/utils/update_previous_refill_end_datetime.py +1 -3
- edc_pharmacy/views/add_to_storage_bin_view.py +2 -6
- edc_pharmacy/views/allocate_to_subject_view.py +7 -21
- edc_pharmacy/views/confirm_stock_from_instance_view.py +2 -6
- edc_pharmacy/views/confirm_stock_from_queryset_view.py +2 -7
- edc_pharmacy/views/confirmation_at_site_view.py +10 -31
- edc_pharmacy/views/dispense_view.py +2 -6
- edc_pharmacy/views/move_to_storage_bin_view.py +2 -6
- edc_pharmacy/views/prepare_and_review_stock_request_view.py +3 -9
- edc_pharmacy/views/print_labels_view.py +1 -3
- edc_pharmacy/views/print_stock_transfer_manifest_view.py +1 -3
- edc_pharmacy/views/transfer_stock_view.py +1 -3
- edc_prn/modelform_mixins.py +1 -3
- edc_prn/prn.py +2 -6
- edc_prn/templatetags/edc_prn_extras.py +4 -8
- edc_protocol/research_protocol_config.py +2 -5
- edc_protocol_incident/admin/protocol_deviation_violation_admin.py +1 -3
- edc_protocol_incident/auth_objects.py +1 -3
- edc_protocol_incident/auths.py +1 -3
- edc_protocol_incident/form_validators/mixins.py +3 -9
- edc_protocol_incident/form_validators/protocol_deviation_violation_form_validator.py +6 -18
- edc_protocol_incident/form_validators/protocol_incident_form_validator.py +3 -8
- edc_protocol_incident/migrations/0001_initial.py +4 -3
- edc_protocol_incident/migrations/0001_squashed_0015_auto_20220927_0401.py +7 -12
- edc_protocol_incident/migrations/0005_protocolincident_historicalprotocolincident_and_more.py +4 -3
- edc_protocol_incident/migrations/0012_auto_20220913_2139.py +3 -9
- edc_protocol_incident/migrations/0020_alter_historicalprotocoldeviationviolation_device_created_and_more.py +9 -25
- edc_protocol_incident/model_mixins/protocol_deviation_violation_model_mixin.py +3 -7
- edc_protocol_incident/model_mixins/protocol_incident_model_mixin.py +1 -3
- edc_protocol_incident/urls.py +1 -3
- edc_pylabels/actions.py +2 -6
- edc_pylabels/admin/label_configuration_admin.py +4 -4
- edc_pylabels/drawing_callable_example.py +1 -3
- edc_pylabels/migrations/0001_initial.py +1 -3
- edc_pylabels/migrations/0002_alter_label_options_label_created_and_more.py +2 -6
- edc_pylabels/migrations/0005_labelconfiguration_delete_label_and_more.py +1 -3
- edc_pylabels/models/label_configuration.py +1 -3
- edc_qareports/migrations/0001_initial.py +3 -4
- edc_qareports/migrations/0005_edcpermissions.py +2 -4
- edc_qareports/migrations/0006_qareportlog.py +2 -1
- edc_qareports/migrations/0007_qareportlog_edc_qarepor_accesse_738ffe_idx.py +1 -3
- edc_qareports/migrations/0017_auto_20240816_0256.py +1 -0
- edc_qareports/model_mixins/note_model_mixin.py +1 -3
- edc_qareports/modeladmin_mixins/list_filters.py +8 -12
- edc_qareports/modeladmin_mixins/note_modeladmin_mixin.py +1 -3
- edc_qareports/modeladmin_mixins/on_study_missing_values_modeladmin_mixin.py +2 -6
- edc_qareports/modeladmin_mixins/qa_report_modeladmin_mixin.py +1 -3
- edc_qareports/sql_generator/crf_case.py +1 -5
- edc_qareports/sql_generator/sql_view_generator.py +1 -3
- edc_qareports/utils.py +2 -6
- edc_randomization/admin.py +1 -3
- edc_randomization/auths.py +2 -6
- edc_randomization/blinding.py +1 -3
- edc_randomization/migrations/0001_initial.py +3 -4
- edc_randomization/migrations/0009_edcpermissions.py +1 -1
- edc_randomization/migrations/0011_alter_edcpermissions_device_created_and_more.py +7 -19
- edc_randomization/model_mixins.py +2 -5
- edc_randomization/randomization_list_importer.py +3 -7
- edc_randomization/randomization_list_verifier.py +2 -7
- edc_randomization/randomizer.py +2 -6
- edc_randomization/site_randomizers.py +1 -3
- edc_randomization/system_checks.py +1 -3
- edc_randomization/utils.py +2 -6
- edc_refusal/admin.py +1 -3
- edc_refusal/forms.py +1 -2
- edc_refusal/migrations/0001_initial.py +2 -1
- edc_refusal/migrations/0002_historicalsubjectrefusal.py +6 -4
- edc_refusal/migrations/0004_refusalreasons_plural_name.py +1 -3
- edc_refusal/migrations/0005_alter_subjectrefusal_options_and_more.py +2 -1
- edc_refusal/migrations/0006_alter_subjectrefusal_managers.py +2 -1
- edc_refusal/migrations/0008_alter_historicalsubjectrefusal_device_created_and_more.py +5 -13
- edc_registration/admin_site.py +1 -3
- edc_registration/migrations/0001_initial.py +3 -4
- edc_registration/migrations/0002_auto_20161127_2226.py +4 -7
- edc_registration/migrations/0004_auto_20161221_0018.py +2 -1
- edc_registration/migrations/0005_auto_20170111_1809.py +2 -1
- edc_registration/migrations/0008_auto_20170810_1032.py +2 -1
- edc_registration/migrations/0012_auto_20180116_1528.py +2 -1
- edc_registration/migrations/0015_auto_20181006_2257.py +1 -1
- edc_registration/migrations/0016_historicalregisteredsubject.py +5 -6
- edc_registration/migrations/0026_historicalregisteredsubject_familiar_name_and_more.py +1 -1
- edc_registration/migrations/0028_alter_registeredsubject_managers.py +1 -1
- edc_registration/migrations/0029_alter_historicalregisteredsubject_device_created_and_more.py +5 -13
- edc_registration/modeladmin_mixins.py +1 -3
- edc_registration/models/registered_subject.py +4 -11
- edc_registration/utils.py +1 -3
- edc_reportable/admin_site.py +1 -3
- edc_reportable/data/normal_data/africa.py +4 -14
- edc_reportable/evaluator.py +2 -6
- edc_reportable/formula.py +2 -6
- edc_reportable/management/commands/export_reportables.py +1 -3
- edc_reportable/migrations/0001_initial.py +3 -9
- edc_reportable/migrations/0003_referencerangecollection_grade1_and_more.py +3 -9
- edc_reportable/migrations/0004_alter_referencerangecollection_grade3_and_more.py +4 -7
- edc_reportable/migrations/0006_alter_gradingdata_revision_and_more.py +8 -19
- edc_reportable/models/mw.py +1 -3
- edc_reportable/models/reference_model_mixins.py +1 -3
- edc_reportable/models/reference_range_collection.py +3 -9
- edc_reportable/post_migrate_signals.py +1 -3
- edc_reportable/reference_range_evaluator.py +4 -11
- edc_reportable/utils/convert_units.py +1 -3
- edc_reportable/utils/get_grade_for_value.py +3 -1
- edc_reportable/utils/get_reference_range_collection.py +2 -2
- edc_reportable/utils/load_data.py +1 -3
- edc_reportable/utils/update_grading_data.py +2 -6
- edc_review_dashboard/migrations/0001_initial.py +1 -1
- edc_review_dashboard/migrations/0003_alter_edcpermissions_device_created_and_more.py +3 -7
- edc_review_dashboard/views/subject_review_listboard_view.py +1 -3
- edc_screening/eligibility.py +1 -3
- edc_screening/fc.py +1 -3
- edc_screening/migrations/0001_initial.py +1 -1
- edc_screening/migrations/0002_alter_edcpermissions_device_created_and_more.py +3 -7
- edc_screening/model_mixins/eligibility_model_mixin.py +1 -3
- edc_screening/model_mixins/screening_fields_model_mixin.py +2 -0
- edc_screening/modelform_mixins.py +1 -3
- edc_search/search_slug.py +2 -6
- edc_search/updater.py +2 -5
- edc_sites/admin/site_model_admin_mixin.py +4 -12
- edc_sites/management/commands/sync_sites.py +1 -3
- edc_sites/migrations/0007_edcpermissions.py +2 -4
- edc_sites/single_site/get_languages.py +1 -3
- edc_sites/site.py +4 -11
- edc_sites/system_checks.py +1 -4
- edc_sites/utils/add_or_update_django_sites.py +1 -3
- edc_subject_dashboard/migrations/0001_initial.py +1 -1
- edc_subject_dashboard/migrations/0002_alter_edcpermissions_device_created_and_more.py +3 -7
- edc_subject_dashboard/requisition_labels.py +1 -3
- edc_subject_dashboard/requisition_report.py +5 -15
- edc_subject_dashboard/requisition_verifier.py +2 -7
- edc_subject_dashboard/templatetags/edc_subject_dashboard_extras.py +2 -6
- edc_subject_dashboard/view_mixins/subject_visit_view_mixin.py +1 -2
- edc_subject_dashboard/view_utils/crf_button.py +1 -3
- edc_subject_dashboard/view_utils/subject_consent_listboard_button.py +1 -3
- edc_subject_dashboard/view_utils/timepoint_status_button.py +1 -3
- edc_subject_dashboard/views/requisition_print_actions_view.py +4 -12
- edc_subject_dashboard/views/requisition_verify_actions_view.py +1 -3
- edc_subject_dashboard/views/subject_dashboard_view.py +1 -3
- edc_timepoint/apps.py +1 -3
- edc_timepoint/timepoint.py +1 -3
- edc_timepoint/timepoint_lookup.py +1 -3
- edc_transfer/form_validators.py +4 -6
- edc_transfer/model_mixins.py +1 -3
- edc_transfer/modelform_mixins.py +1 -3
- edc_unblinding/action_items.py +1 -3
- edc_unblinding/admin_site.py +1 -3
- edc_unblinding/migrations/0001_initial.py +6 -4
- edc_unblinding/migrations/0002_auto_20210908_2318.py +1 -1
- edc_unblinding/migrations/0009_alter_unblindingrequest_managers_and_more.py +2 -1
- edc_unblinding/migrations/0010_alter_historicalunblindingrequest_device_created_and_more.py +9 -25
- edc_unblinding/models/unblinding_request.py +1 -3
- edc_unblinding/models/unblinding_review.py +1 -3
- edc_utils/age.py +1 -3
- edc_utils/date.py +1 -3
- edc_utils/paths_for_urlpatterns.py +1 -3
- edc_utils/show_urls.py +1 -3
- edc_utils/text.py +1 -2
- edc_view_utils/model_button.py +5 -13
- edc_view_utils/query_button.py +1 -3
- edc_visit_schedule/admin/subject_schedule_history_admin.py +1 -3
- edc_visit_schedule/baseline.py +1 -3
- edc_visit_schedule/migrations/0001_initial.py +3 -4
- edc_visit_schedule/migrations/0003_historicalvisitschedule_visitschedule.py +1 -3
- edc_visit_schedule/migrations/0004_auto_20190629_1800.py +1 -3
- edc_visit_schedule/migrations/0011_alter_historicalvisitschedule_device_created_and_more.py +7 -19
- edc_visit_schedule/migrations/0012_alter_subjectschedulehistory_managers_and_more.py +2 -1
- edc_visit_schedule/migrations/0015_historicalonschedule_offschedule_onschedule.py +9 -13
- edc_visit_schedule/migrations/0017_alter_onschedule_managers.py +2 -1
- edc_visit_schedule/model_mixins/crf/crf_schedule_model_mixin.py +1 -1
- edc_visit_schedule/model_mixins/off_schedule_model_mixin.py +2 -6
- edc_visit_schedule/model_mixins/on_schedule_model_mixin.py +1 -3
- edc_visit_schedule/modelform_mixins/off_schedule_modelform_mixin.py +1 -3
- edc_visit_schedule/models/subject_schedule_history.py +3 -8
- edc_visit_schedule/ordered_collection.py +1 -3
- edc_visit_schedule/schedule/schedule.py +6 -17
- edc_visit_schedule/simple_model_validator.py +3 -8
- edc_visit_schedule/site_visit_schedules.py +5 -15
- edc_visit_schedule/subject_schedule.py +4 -16
- edc_visit_schedule/system_checks.py +1 -3
- edc_visit_schedule/utils.py +8 -17
- edc_visit_schedule/view_mixins.py +4 -10
- edc_visit_schedule/visit/crf.py +1 -2
- edc_visit_schedule/visit/requisition.py +1 -3
- edc_visit_schedule/visit/visit.py +6 -16
- edc_visit_schedule/visit/window_period.py +3 -3
- edc_visit_schedule/visit_schedule/visit_schedule.py +2 -5
- edc_visit_tracking/crf_date_validator.py +1 -2
- edc_visit_tracking/form_validators/visit_form_validator.py +2 -8
- edc_visit_tracking/form_validators/visit_missed_form_validator.py +3 -9
- edc_visit_tracking/migrations/0003_auto_20220913_2139.py +2 -6
- edc_visit_tracking/migrations/0004_subjectvisit_subjectvisitmissedreasons_extra_value_and_more.py +8 -16
- edc_visit_tracking/model_mixins/base/visit_methods_model_mixin.py +2 -6
- edc_visit_tracking/model_mixins/crfs/visit_tracking_crf_model_mixin.py +1 -3
- edc_visit_tracking/model_mixins/requisitions/visit_tracking_requisition_model_mixin.py +1 -3
- edc_visit_tracking/model_mixins/subject_visit_missed_model_mixin.py +1 -3
- edc_visit_tracking/model_mixins/visit_model_mixin/visit_model_fields_mixin.py +1 -2
- edc_visit_tracking/modeladmin_mixins/crf_model_admin_mixin.py +4 -8
- edc_visit_tracking/modeladmin_mixins/visit_model_admin_mixin.py +4 -6
- edc_visit_tracking/modelform_mixins/crf/visit_tracking_crf_modelform_mixin.py +2 -6
- edc_visit_tracking/modelform_mixins/utils.py +1 -3
- edc_visit_tracking/modelform_mixins/visit_tracking_modelform_mixin.py +1 -2
- edc_visit_tracking/models/signals.py +1 -3
- edc_visit_tracking/stubs.py +1 -3
- edc_visit_tracking/utils.py +1 -2
- edc_visit_tracking/view_utils/related_visit_button.py +1 -3
- edc_visit_tracking/visit_sequence.py +1 -3
- edc_vitals/__init__.py +2 -0
- edc_vitals/apps.py +6 -0
- edc_vitals/calculators/__init__.py +1 -0
- edc_vitals/calculators/bmi.py +70 -0
- edc_vitals/form_validators/__init__.py +5 -0
- edc_vitals/form_validators/blood_pressure_form_validator_mixin.py +40 -0
- edc_vitals/form_validators/bmi_form_validator_mixin.py +19 -0
- edc_vitals/form_validators/weight_height_with_bmi_form_validator_mixin.py +13 -0
- edc_vitals/migrations/__init__.py +0 -0
- edc_vitals/model_mixins/__init__.py +5 -0
- edc_vitals/model_mixins/blood_pressure_model_mixin.py +80 -0
- edc_vitals/model_mixins/weight_height_bmi_model_mixin.py +42 -0
- edc_vitals/models/__init__.py +10 -0
- edc_vitals/models/fields/__init__.py +7 -0
- edc_vitals/models/fields/blood_pressure.py +36 -0
- edc_vitals/models/fields/heart_rate.py +22 -0
- edc_vitals/models/fields/height.py +26 -0
- edc_vitals/models/fields/respiratory_rate.py +22 -0
- edc_vitals/models/fields/temperature.py +26 -0
- edc_vitals/models/fields/waist_circumference.py +23 -0
- edc_vitals/models/fields/weight.py +26 -0
- edc_vitals/utils.py +51 -0
- edc_vitals/validators.py +5 -0
- edc_lab_results/model_mixin_factory/__init__.py +0 -2
- {clinicedc-2.0.1.dist-info → clinicedc-2.0.3.dist-info}/licenses/LICENSE +0 -0
edc_appointment/utils.py
CHANGED
|
@@ -291,9 +291,7 @@ def reset_visit_code_sequence_or_pass(
|
|
|
291
291
|
f"{subject_identifier} {visit_code}: {actual=} {expected=} ...\n"
|
|
292
292
|
)
|
|
293
293
|
# reset visit code sequence for this visit code
|
|
294
|
-
get_crf_metadata_model_cls().objects.filter(
|
|
295
|
-
visit_code_sequence__gt=0, **opts
|
|
296
|
-
).delete()
|
|
294
|
+
get_crf_metadata_model_cls().objects.filter(visit_code_sequence__gt=0, **opts).delete()
|
|
297
295
|
get_requisition_metadata_model_cls().objects.filter(
|
|
298
296
|
visit_code_sequence__gt=0, **opts
|
|
299
297
|
).delete()
|
|
@@ -309,9 +307,7 @@ def reset_visit_code_sequence_or_pass(
|
|
|
309
307
|
obj.save_base(update_fields=["visit_code_sequence"])
|
|
310
308
|
if getattr(obj, "related_visit", None):
|
|
311
309
|
obj.related_visit.visit_code_sequence = obj.visit_code_sequence
|
|
312
|
-
obj.related_visit.save_base(
|
|
313
|
-
update_fields=["visit_code_sequence"]
|
|
314
|
-
)
|
|
310
|
+
obj.related_visit.save_base(update_fields=["visit_code_sequence"])
|
|
315
311
|
obj.related_visit.metadata_create()
|
|
316
312
|
|
|
317
313
|
# reset sequence order by appt_datetime
|
|
@@ -325,9 +321,7 @@ def reset_visit_code_sequence_or_pass(
|
|
|
325
321
|
obj.save_base(update_fields=["visit_code_sequence"])
|
|
326
322
|
if getattr(obj, "related_visit", None):
|
|
327
323
|
obj.related_visit.visit_code_sequence = index
|
|
328
|
-
obj.related_visit.save_base(
|
|
329
|
-
update_fields=["visit_code_sequence"]
|
|
330
|
-
)
|
|
324
|
+
obj.related_visit.save_base(update_fields=["visit_code_sequence"])
|
|
331
325
|
obj.related_visit.metadata_create()
|
|
332
326
|
|
|
333
327
|
except IntegrityError:
|
|
@@ -385,10 +379,7 @@ def update_appt_status(appointment: Appointment, save: bool | None = None):
|
|
|
385
379
|
relative to the visit tracking model and CRFs and
|
|
386
380
|
requisitions
|
|
387
381
|
"""
|
|
388
|
-
if
|
|
389
|
-
appointment.appt_status == CANCELLED_APPT
|
|
390
|
-
or appointment.appt_status == SKIPPED_APPT
|
|
391
|
-
):
|
|
382
|
+
if appointment.appt_status == CANCELLED_APPT or appointment.appt_status == SKIPPED_APPT:
|
|
392
383
|
pass
|
|
393
384
|
elif not appointment.related_visit:
|
|
394
385
|
appointment.appt_status = NEW_APPT
|
|
@@ -451,9 +442,7 @@ def get_previous_appointment(
|
|
|
451
442
|
return previous_appt
|
|
452
443
|
|
|
453
444
|
|
|
454
|
-
def get_next_appointment(
|
|
455
|
-
appointment: Appointment, include_interim=None
|
|
456
|
-
) -> Appointment | None:
|
|
445
|
+
def get_next_appointment(appointment: Appointment, include_interim=None) -> Appointment | None:
|
|
457
446
|
"""Returns the next appointment model instance,
|
|
458
447
|
or None, in this schedule.
|
|
459
448
|
|
|
@@ -511,9 +500,7 @@ def raise_on_appt_datetime_not_in_window(
|
|
|
511
500
|
appt_datetime: datetime | None = None,
|
|
512
501
|
baseline_timepoint_datetime: datetime | None = None,
|
|
513
502
|
) -> None:
|
|
514
|
-
if appointment.appt_status != CANCELLED_APPT and not is_baseline(
|
|
515
|
-
instance=appointment
|
|
516
|
-
):
|
|
503
|
+
if appointment.appt_status != CANCELLED_APPT and not is_baseline(instance=appointment):
|
|
517
504
|
baseline_timepoint_datetime = baseline_timepoint_datetime or (
|
|
518
505
|
appointment.__class__.objects.first_appointment(
|
|
519
506
|
subject_identifier=appointment.subject_identifier,
|
|
@@ -555,9 +542,7 @@ def get_window_gap_days(appointment) -> int:
|
|
|
555
542
|
return gap_days
|
|
556
543
|
|
|
557
544
|
|
|
558
|
-
def appt_datetime_in_gap(
|
|
559
|
-
appointment: Appointment, suggested_appt_datetime: datetime
|
|
560
|
-
) -> bool:
|
|
545
|
+
def appt_datetime_in_gap(appointment: Appointment, suggested_appt_datetime: datetime) -> bool:
|
|
561
546
|
"""Return True if datetime falls in a gap between this and the
|
|
562
547
|
next appointment window.
|
|
563
548
|
"""
|
|
@@ -575,8 +560,7 @@ def appt_datetime_in_gap(
|
|
|
575
560
|
def get_max_window_gap_to_lower(appointment) -> int:
|
|
576
561
|
if (
|
|
577
562
|
appointment.visit.max_window_gap_to_lower is not None
|
|
578
|
-
and appointment.visit.max_window_gap_to_lower
|
|
579
|
-
< get_default_max_visit_window_gap()
|
|
563
|
+
and appointment.visit.max_window_gap_to_lower < get_default_max_visit_window_gap()
|
|
580
564
|
):
|
|
581
565
|
max_gap = appointment.visit.max_window_gap_to_lower
|
|
582
566
|
else:
|
|
@@ -759,18 +743,14 @@ def update_appt_status_for_timepoint(related_visit: RelatedVisitModel) -> None:
|
|
|
759
743
|
if related_visit.appointment.appt_status == COMPLETE_APPT:
|
|
760
744
|
if (
|
|
761
745
|
related_visit.metadata[CRF].filter(entry_status=REQUIRED).exists()
|
|
762
|
-
or related_visit.metadata[REQUISITION]
|
|
763
|
-
.filter(entry_status=REQUIRED)
|
|
764
|
-
.exists()
|
|
746
|
+
or related_visit.metadata[REQUISITION].filter(entry_status=REQUIRED).exists()
|
|
765
747
|
):
|
|
766
748
|
related_visit.appointment.appt_status = INCOMPLETE_APPT
|
|
767
749
|
related_visit.appointment.save_base(update_fields=["appt_status"])
|
|
768
750
|
elif related_visit.appointment.appt_status == INCOMPLETE_APPT:
|
|
769
751
|
if (
|
|
770
752
|
not related_visit.metadata[CRF].filter(entry_status=REQUIRED).exists()
|
|
771
|
-
and not related_visit.metadata[REQUISITION]
|
|
772
|
-
.filter(entry_status=REQUIRED)
|
|
773
|
-
.exists()
|
|
753
|
+
and not related_visit.metadata[REQUISITION].filter(entry_status=REQUIRED).exists()
|
|
774
754
|
):
|
|
775
755
|
related_visit.appointment.appt_status = COMPLETE_APPT
|
|
776
756
|
related_visit.appointment.save_base(update_fields=["appt_status"])
|
|
@@ -854,9 +834,7 @@ def validate_date_is_on_clinic_day(
|
|
|
854
834
|
"mon": day_abbr[calendar.MONDAY],
|
|
855
835
|
"fri": day_abbr[calendar.FRIDAY],
|
|
856
836
|
"day": day_abbr[
|
|
857
|
-
calendar.weekday(
|
|
858
|
-
appt_date.year, appt_date.month, appt_date.day
|
|
859
|
-
)
|
|
837
|
+
calendar.weekday(appt_date.year, appt_date.month, appt_date.day)
|
|
860
838
|
],
|
|
861
839
|
}
|
|
862
840
|
},
|
|
@@ -50,9 +50,7 @@ class AppointmentViewMixin:
|
|
|
50
50
|
if self.appointment.related_visit:
|
|
51
51
|
report_datetime = self.appointment.related_visit.report_datetime
|
|
52
52
|
kwargs.update(report_datetime=report_datetime)
|
|
53
|
-
has_call_manager = (
|
|
54
|
-
True if django_apps.app_configs.get("edc_call_manager") else False
|
|
55
|
-
)
|
|
53
|
+
has_call_manager = True if django_apps.app_configs.get("edc_call_manager") else False
|
|
56
54
|
kwargs.update(
|
|
57
55
|
appointment=self.appointment,
|
|
58
56
|
appointments=self.appointments,
|
|
@@ -103,9 +101,7 @@ class AppointmentViewMixin:
|
|
|
103
101
|
except ObjectDoesNotExist:
|
|
104
102
|
if opts := self.appointment_options:
|
|
105
103
|
try:
|
|
106
|
-
self._appointment = self.appointment_model_cls.objects.get(
|
|
107
|
-
**opts
|
|
108
|
-
)
|
|
104
|
+
self._appointment = self.appointment_model_cls.objects.get(**opts)
|
|
109
105
|
except ObjectDoesNotExist:
|
|
110
106
|
pass
|
|
111
107
|
return self._appointment
|
edc_auth/admin/list_filters.py
CHANGED
|
@@ -17,9 +17,7 @@ class SitesListFilter(SimpleListFilter):
|
|
|
17
17
|
"""Returns a queryset if the site name is in the list of sites"""
|
|
18
18
|
qs = None
|
|
19
19
|
if self.value():
|
|
20
|
-
qs = get_user_model().objects.filter(
|
|
21
|
-
userprofile__sites__name__in=[self.value()]
|
|
22
|
-
)
|
|
20
|
+
qs = get_user_model().objects.filter(userprofile__sites__name__in=[self.value()])
|
|
23
21
|
return qs
|
|
24
22
|
|
|
25
23
|
|
|
@@ -39,9 +37,7 @@ class CountriesListFilter(SimpleListFilter):
|
|
|
39
37
|
if self.value():
|
|
40
38
|
qs = (
|
|
41
39
|
get_user_model()
|
|
42
|
-
.objects.filter(
|
|
43
|
-
userprofile__sites__siteprofile__country__in=[self.value()]
|
|
44
|
-
)
|
|
40
|
+
.objects.filter(userprofile__sites__siteprofile__country__in=[self.value()])
|
|
45
41
|
.distinct()
|
|
46
42
|
)
|
|
47
43
|
return qs
|
edc_auth/admin/role_admin.py
CHANGED
|
@@ -12,9 +12,7 @@ from ..models import Role
|
|
|
12
12
|
|
|
13
13
|
@admin.register(Role, site=edc_auth_admin)
|
|
14
14
|
class RoleAdmin(TemplatesModelAdminMixin, admin.ModelAdmin):
|
|
15
|
-
fieldsets = (
|
|
16
|
-
(None, ({"fields": ("display_name", "name", "display_index", "groups")})),
|
|
17
|
-
)
|
|
15
|
+
fieldsets = ((None, ({"fields": ("display_name", "name", "display_index", "groups")})),)
|
|
18
16
|
|
|
19
17
|
list_display_links: Tuple[str, ...] = ("display_name", "group_list")
|
|
20
18
|
|
edc_auth/admin/user_admin.py
CHANGED
|
@@ -23,9 +23,7 @@ def send_new_credentials_to_user_action(modeladmin, request, queryset): # noqa
|
|
|
23
23
|
messages.error(request, "You do not have permissions to run this action.")
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
send_new_credentials_to_user_action.short_description =
|
|
27
|
-
"Reset password and email to user"
|
|
28
|
-
)
|
|
26
|
+
send_new_credentials_to_user_action.short_description = "Reset password and email to user"
|
|
29
27
|
|
|
30
28
|
|
|
31
29
|
@admin.register(User, site=edc_auth_admin)
|
|
@@ -85,12 +83,8 @@ class UserAdmin(TemplatesModelAdminMixin, BaseUserAdmin):
|
|
|
85
83
|
role_group_names = []
|
|
86
84
|
for role in obj.userprofile.roles.all():
|
|
87
85
|
roles.append(role)
|
|
88
|
-
role_group_names.extend(
|
|
89
|
-
|
|
90
|
-
)
|
|
91
|
-
extra_groups = [
|
|
92
|
-
obj for obj in obj.groups.all() if obj.name not in role_group_names
|
|
93
|
-
]
|
|
86
|
+
role_group_names.extend([grp.name for grp in role.groups.all().order_by("name")])
|
|
87
|
+
extra_groups = [obj for obj in obj.groups.all() if obj.name not in role_group_names]
|
|
94
88
|
context = dict(
|
|
95
89
|
role_names=[role.display_name for role in roles],
|
|
96
90
|
extra_group_names=[grp.name.replace("_", " ") for grp in extra_groups],
|
|
@@ -101,9 +95,7 @@ class UserAdmin(TemplatesModelAdminMixin, BaseUserAdmin):
|
|
|
101
95
|
@admin.display(description="Sites")
|
|
102
96
|
def sites(self, obj=None) -> str:
|
|
103
97
|
country_sites = {}
|
|
104
|
-
for site in obj.userprofile.sites.all().order_by(
|
|
105
|
-
"siteprofile__country", "name"
|
|
106
|
-
):
|
|
98
|
+
for site in obj.userprofile.sites.all().order_by("siteprofile__country", "name"):
|
|
107
99
|
country_name = site.siteprofile.country.replace("_", " ").title()
|
|
108
100
|
site_name = site.name.replace("_", " ").title()
|
|
109
101
|
try:
|
|
@@ -50,12 +50,9 @@ class UserProfileAdmin(TemplatesModelAdminMixin, admin.ModelAdmin):
|
|
|
50
50
|
@staticmethod
|
|
51
51
|
def user_email_notifications(obj=None):
|
|
52
52
|
display_names = [
|
|
53
|
-
o.display_name
|
|
54
|
-
for o in obj.email_notifications.all().order_by("display_name")
|
|
53
|
+
o.display_name for o in obj.email_notifications.all().order_by("display_name")
|
|
55
54
|
]
|
|
56
|
-
return format_html(
|
|
57
|
-
"{}", mark_safe("<BR>".join(display_names))
|
|
58
|
-
) # nosec B703 B308
|
|
55
|
+
return format_html("{}", mark_safe("<BR>".join(display_names))) # nosec B703 B308
|
|
59
56
|
|
|
60
57
|
@staticmethod
|
|
61
58
|
def user_sms_notifications(obj=None):
|
|
@@ -46,9 +46,7 @@ class AuthUpdater:
|
|
|
46
46
|
self.verbose = verbose
|
|
47
47
|
self.apps = apps
|
|
48
48
|
if self.verbose:
|
|
49
|
-
sys.stdout.write(
|
|
50
|
-
style.MIGRATE_HEADING("Updating groups and permissions:\n")
|
|
51
|
-
)
|
|
49
|
+
sys.stdout.write(style.MIGRATE_HEADING("Updating groups and permissions:\n"))
|
|
52
50
|
self.group_updater = self.group_updater_cls(
|
|
53
51
|
groups=groups,
|
|
54
52
|
pii_models=pii_models,
|
|
@@ -166,9 +166,7 @@ class GroupUpdater:
|
|
|
166
166
|
try:
|
|
167
167
|
app_label, _codename = codename.split(".")
|
|
168
168
|
except ValueError as e:
|
|
169
|
-
raise PermissionsCodenameError(
|
|
170
|
-
f"Invalid dotted codename. {e} Got {codename}."
|
|
171
|
-
)
|
|
169
|
+
raise PermissionsCodenameError(f"Invalid dotted codename. {e} Got {codename}.")
|
|
172
170
|
else:
|
|
173
171
|
try:
|
|
174
172
|
self.apps.get_app_config(app_label)
|
|
@@ -221,9 +219,7 @@ class GroupUpdater:
|
|
|
221
219
|
except LookupError as e:
|
|
222
220
|
warn(f"{e}. Got {model}")
|
|
223
221
|
else:
|
|
224
|
-
content_type = self.content_type_model_cls.objects.get_for_model(
|
|
225
|
-
model_cls
|
|
226
|
-
)
|
|
222
|
+
content_type = self.content_type_model_cls.objects.get_for_model(model_cls)
|
|
227
223
|
for codename_tpl in codename_tuples:
|
|
228
224
|
app_label, codename, name = self.get_from_codename_tuple(
|
|
229
225
|
codename_tpl, model_cls._meta.app_label
|
|
@@ -250,9 +246,7 @@ class GroupUpdater:
|
|
|
250
246
|
f"Unable to verify codename. {e} Got '{app_label}.{codename}'"
|
|
251
247
|
)
|
|
252
248
|
except MultipleObjectsReturned as e:
|
|
253
|
-
self.delete_and_raise_on_duplicate_codenames(
|
|
254
|
-
codename, app_label, exception=e
|
|
255
|
-
)
|
|
249
|
+
self.delete_and_raise_on_duplicate_codenames(codename, app_label, exception=e)
|
|
256
250
|
return permission
|
|
257
251
|
|
|
258
252
|
def delete_and_raise_on_duplicate_codenames(
|
edc_auth/forms.py
CHANGED
|
@@ -41,9 +41,7 @@ class UserProfileForm(forms.ModelForm):
|
|
|
41
41
|
codenames = get_codenames_for_user(
|
|
42
42
|
user=self.cleaned_data.get("user"), roles=self.cleaned_data.get("roles")
|
|
43
43
|
)
|
|
44
|
-
if c := [
|
|
45
|
-
c for c in codenames if "add_" in c or "change_" in c or "delete_" in c
|
|
46
|
-
]:
|
|
44
|
+
if c := [c for c in codenames if "add_" in c or "change_" in c or "delete_" in c]:
|
|
47
45
|
raise forms.ValidationError(
|
|
48
46
|
{
|
|
49
47
|
"is_multisite_viewer": (
|
edc_auth/get_app_codenames.py
CHANGED
|
@@ -5,9 +5,7 @@ from django.apps import apps as django_apps
|
|
|
5
5
|
|
|
6
6
|
def get_models(app_config, exclude_models: list[str] | None):
|
|
7
7
|
exclude_models = exclude_models or []
|
|
8
|
-
return [
|
|
9
|
-
m for m in app_config.get_models() if m._meta.label_lower not in exclude_models
|
|
10
|
-
]
|
|
8
|
+
return [m for m in app_config.get_models() if m._meta.label_lower not in exclude_models]
|
|
11
9
|
|
|
12
10
|
|
|
13
11
|
def get_app_codenames(
|
edc_auth/import_users.py
CHANGED
|
@@ -111,9 +111,7 @@ def import_users(
|
|
|
111
111
|
opts.update(email=csv_data.get("email"))
|
|
112
112
|
opts.update(alternate_email=csv_data.get("alternate_email"))
|
|
113
113
|
opts.update(job_title=csv_data.get("job_title"))
|
|
114
|
-
opts.update(
|
|
115
|
-
is_active=True if csv_data.get("is_active") == "True" else False
|
|
116
|
-
)
|
|
114
|
+
opts.update(is_active=True if csv_data.get("is_active") == "True" else False)
|
|
117
115
|
opts.update(is_staff=True if csv_data.get("is_staff") == "True" else False)
|
|
118
116
|
UserImporter(
|
|
119
117
|
resource_name=resource_name,
|
|
@@ -177,12 +175,8 @@ class UserImporter:
|
|
|
177
175
|
self.resend_as_newly_created = resend_as_new
|
|
178
176
|
self.test_email_address = test_email_address
|
|
179
177
|
self.username = username or self.get_username()
|
|
180
|
-
self.created_email_template =
|
|
181
|
-
|
|
182
|
-
)
|
|
183
|
-
self.updated_email_template = (
|
|
184
|
-
updated_email_template or self.updated_email_template
|
|
185
|
-
)
|
|
178
|
+
self.created_email_template = created_email_template or self.created_email_template
|
|
179
|
+
self.updated_email_template = updated_email_template or self.updated_email_template
|
|
186
180
|
self.validate_username()
|
|
187
181
|
if ACCOUNT_MANAGER_ROLE in role_names:
|
|
188
182
|
site_names = [s.name for s in Site.objects.all()]
|
|
@@ -7,9 +7,7 @@ class Command(BaseCommand):
|
|
|
7
7
|
help = "Export users to a CSV file in the current directory"
|
|
8
8
|
|
|
9
9
|
def add_arguments(self, parser):
|
|
10
|
-
parser.add_argument(
|
|
11
|
-
"--csvfile", default=None, dest="csvfile", help="CSV filename"
|
|
12
|
-
)
|
|
10
|
+
parser.add_argument("--csvfile", default=None, dest="csvfile", help="CSV filename")
|
|
13
11
|
|
|
14
12
|
parser.add_argument(
|
|
15
13
|
"--verbose",
|
|
@@ -33,6 +33,4 @@ class Command(BaseCommand):
|
|
|
33
33
|
else:
|
|
34
34
|
p = PasswordSetter(super_username=options["super_user"])
|
|
35
35
|
p.reset_user(username=options["username"])
|
|
36
|
-
sys.stdout.write(
|
|
37
|
-
f"\nYour password has been reset and emailed to {user.email}\n"
|
|
38
|
-
)
|
|
36
|
+
sys.stdout.write(f"\nYour password has been reset and emailed to {user.email}\n")
|
|
@@ -249,9 +249,7 @@ class Migration(migrations.Migration):
|
|
|
249
249
|
help_text="e.g. +1234567890",
|
|
250
250
|
max_length=25,
|
|
251
251
|
null=True,
|
|
252
|
-
validators=[
|
|
253
|
-
django.core.validators.RegexValidator(regex="^\\+\\d+")
|
|
254
|
-
],
|
|
252
|
+
validators=[django.core.validators.RegexValidator(regex="^\\+\\d+")],
|
|
255
253
|
),
|
|
256
254
|
),
|
|
257
255
|
(
|
|
@@ -453,9 +451,7 @@ class Migration(migrations.Migration):
|
|
|
453
451
|
),
|
|
454
452
|
(
|
|
455
453
|
"device_created",
|
|
456
|
-
models.CharField(
|
|
457
|
-
blank=True, max_length=10, verbose_name="Device created"
|
|
458
|
-
),
|
|
454
|
+
models.CharField(blank=True, max_length=10, verbose_name="Device created"),
|
|
459
455
|
),
|
|
460
456
|
(
|
|
461
457
|
"device_modified",
|
|
@@ -483,16 +479,12 @@ class Migration(migrations.Migration):
|
|
|
483
479
|
migrations.AlterField(
|
|
484
480
|
model_name="role",
|
|
485
481
|
name="device_created",
|
|
486
|
-
field=models.CharField(
|
|
487
|
-
blank=True, max_length=10, verbose_name="Device created"
|
|
488
|
-
),
|
|
482
|
+
field=models.CharField(blank=True, max_length=10, verbose_name="Device created"),
|
|
489
483
|
),
|
|
490
484
|
migrations.AlterField(
|
|
491
485
|
model_name="role",
|
|
492
486
|
name="device_modified",
|
|
493
|
-
field=models.CharField(
|
|
494
|
-
blank=True, max_length=10, verbose_name="Device modified"
|
|
495
|
-
),
|
|
487
|
+
field=models.CharField(blank=True, max_length=10, verbose_name="Device modified"),
|
|
496
488
|
),
|
|
497
489
|
migrations.AlterField(
|
|
498
490
|
model_name="role",
|
|
@@ -13,9 +13,7 @@ class Migration(migrations.Migration):
|
|
|
13
13
|
migrations.RemoveIndex(model_name="role", name="edc_auth_ro_id_587a9b_idx"),
|
|
14
14
|
migrations.RemoveField(model_name="role", name="field_name"),
|
|
15
15
|
migrations.RemoveField(model_name="role", name="version"),
|
|
16
|
-
migrations.RenameField(
|
|
17
|
-
model_name="role", old_name="name", new_name="display_name"
|
|
18
|
-
),
|
|
16
|
+
migrations.RenameField(model_name="role", old_name="name", new_name="display_name"),
|
|
19
17
|
migrations.AddIndex(
|
|
20
18
|
model_name="role",
|
|
21
19
|
index=models.Index(
|
|
@@ -7,9 +7,7 @@ class Migration(migrations.Migration):
|
|
|
7
7
|
dependencies = [("edc_auth", "0015_auto_20191026_2149")]
|
|
8
8
|
|
|
9
9
|
operations = [
|
|
10
|
-
migrations.RenameField(
|
|
11
|
-
model_name="role", old_name="short_name", new_name="name"
|
|
12
|
-
),
|
|
10
|
+
migrations.RenameField(model_name="role", old_name="short_name", new_name="name"),
|
|
13
11
|
migrations.AlterField(
|
|
14
12
|
model_name="role",
|
|
15
13
|
name="display_name",
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Generated by Django 3.2.13 on 2022-08-24 20:47
|
|
2
2
|
|
|
3
3
|
import _socket
|
|
4
|
-
from django.db import migrations, models
|
|
5
4
|
import django_audit_fields.fields.hostname_modification_field
|
|
6
5
|
import django_audit_fields.fields.userfield
|
|
7
6
|
import django_audit_fields.fields.uuid_auto_field
|
|
8
7
|
import django_audit_fields.models.audit_model_mixin
|
|
9
8
|
import django_revision.revision_field
|
|
9
|
+
from django.db import migrations, models
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class Migration(migrations.Migration):
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Generated by Django 4.2.4 on 2023-08-23 01:13
|
|
2
2
|
|
|
3
3
|
import _socket
|
|
4
|
-
from django.db import migrations, models
|
|
5
4
|
import django_audit_fields.fields.hostname_modification_field
|
|
5
|
+
from django.db import migrations, models
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class Migration(migrations.Migration):
|
|
@@ -14,16 +14,12 @@ class Migration(migrations.Migration):
|
|
|
14
14
|
migrations.AlterField(
|
|
15
15
|
model_name="edcpermissions",
|
|
16
16
|
name="device_created",
|
|
17
|
-
field=models.CharField(
|
|
18
|
-
blank=True, max_length=10, verbose_name="Device created"
|
|
19
|
-
),
|
|
17
|
+
field=models.CharField(blank=True, max_length=10, verbose_name="Device created"),
|
|
20
18
|
),
|
|
21
19
|
migrations.AlterField(
|
|
22
20
|
model_name="edcpermissions",
|
|
23
21
|
name="device_modified",
|
|
24
|
-
field=models.CharField(
|
|
25
|
-
blank=True, max_length=10, verbose_name="Device modified"
|
|
26
|
-
),
|
|
22
|
+
field=models.CharField(blank=True, max_length=10, verbose_name="Device modified"),
|
|
27
23
|
),
|
|
28
24
|
migrations.AlterField(
|
|
29
25
|
model_name="edcpermissions",
|
|
@@ -49,16 +45,12 @@ class Migration(migrations.Migration):
|
|
|
49
45
|
migrations.AlterField(
|
|
50
46
|
model_name="role",
|
|
51
47
|
name="device_created",
|
|
52
|
-
field=models.CharField(
|
|
53
|
-
blank=True, max_length=10, verbose_name="Device created"
|
|
54
|
-
),
|
|
48
|
+
field=models.CharField(blank=True, max_length=10, verbose_name="Device created"),
|
|
55
49
|
),
|
|
56
50
|
migrations.AlterField(
|
|
57
51
|
model_name="role",
|
|
58
52
|
name="device_modified",
|
|
59
|
-
field=models.CharField(
|
|
60
|
-
blank=True, max_length=10, verbose_name="Device modified"
|
|
61
|
-
),
|
|
53
|
+
field=models.CharField(blank=True, max_length=10, verbose_name="Device modified"),
|
|
62
54
|
),
|
|
63
55
|
migrations.AlterField(
|
|
64
56
|
model_name="role",
|
edc_auth/models/__init__.py
CHANGED
|
@@ -10,7 +10,5 @@ from .signals import (
|
|
|
10
10
|
)
|
|
11
11
|
from .user_profile import UserProfile
|
|
12
12
|
|
|
13
|
-
if settings.APP_NAME == "edc_auth" and (
|
|
14
|
-
"test" in sys.argv or "runtests.py" in sys.argv
|
|
15
|
-
):
|
|
13
|
+
if settings.APP_NAME == "edc_auth" and ("test" in sys.argv or "runtests.py" in sys.argv):
|
|
16
14
|
from ..tests.models import * # noqa
|
edc_auth/models/signals.py
CHANGED
|
@@ -6,9 +6,7 @@ from django.dispatch import receiver
|
|
|
6
6
|
from .user_profile import UserProfile
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
@receiver(
|
|
10
|
-
post_save, weak=False, sender=User, dispatch_uid="update_user_profile_on_post_save"
|
|
11
|
-
)
|
|
9
|
+
@receiver(post_save, weak=False, sender=User, dispatch_uid="update_user_profile_on_post_save")
|
|
12
10
|
def update_user_profile_on_post_save(sender, instance, raw, **kwargs):
|
|
13
11
|
if not raw:
|
|
14
12
|
try:
|
|
@@ -17,9 +15,7 @@ def update_user_profile_on_post_save(sender, instance, raw, **kwargs):
|
|
|
17
15
|
UserProfile.objects.create(user=instance)
|
|
18
16
|
|
|
19
17
|
|
|
20
|
-
@receiver(
|
|
21
|
-
m2m_changed, weak=False, dispatch_uid="update_user_groups_on_role_m2m_changed"
|
|
22
|
-
)
|
|
18
|
+
@receiver(m2m_changed, weak=False, dispatch_uid="update_user_groups_on_role_m2m_changed")
|
|
23
19
|
def update_user_groups_on_role_m2m_changed(sender, action, instance, pk_set, **kwargs):
|
|
24
20
|
try:
|
|
25
21
|
through = instance.roles.through
|
edc_auth/models/user_profile.py
CHANGED
|
@@ -34,9 +34,7 @@ class UserProfile(NotificationUserProfileModelMixin, models.Model):
|
|
|
34
34
|
|
|
35
35
|
job_title = models.CharField(max_length=100, null=True, blank=True)
|
|
36
36
|
|
|
37
|
-
alternate_email = models.EmailField(
|
|
38
|
-
_("Alternate email address"), blank=True, null=True
|
|
39
|
-
)
|
|
37
|
+
alternate_email = models.EmailField(_("Alternate email address"), blank=True, null=True)
|
|
40
38
|
|
|
41
39
|
mobile = models.CharField(
|
|
42
40
|
max_length=25,
|
edc_auth/password_setter.py
CHANGED
|
@@ -58,9 +58,7 @@ class PasswordSetter:
|
|
|
58
58
|
self._reset(users)
|
|
59
59
|
|
|
60
60
|
def reset_users(self, usernames: List[str]) -> None:
|
|
61
|
-
users = User.objects.filter(
|
|
62
|
-
username__in=usernames, is_active=True, is_staff=True
|
|
63
|
-
)
|
|
61
|
+
users = User.objects.filter(username__in=usernames, is_active=True, is_staff=True)
|
|
64
62
|
self._reset(users)
|
|
65
63
|
|
|
66
64
|
def reset_user(self, username: str) -> None:
|
edc_auth/system_checks.py
CHANGED
|
@@ -14,11 +14,7 @@ def check_etc_dir(app_configs, **kwargs) -> list[CheckMessage]:
|
|
|
14
14
|
except AttributeError:
|
|
15
15
|
pass
|
|
16
16
|
else:
|
|
17
|
-
if (
|
|
18
|
-
not settings.DEBUG
|
|
19
|
-
and settings.ETC_DIR
|
|
20
|
-
and not settings.ETC_DIR.startswith("/etc")
|
|
21
|
-
):
|
|
17
|
+
if not settings.DEBUG and settings.ETC_DIR and not settings.ETC_DIR.startswith("/etc"):
|
|
22
18
|
errors.append(
|
|
23
19
|
Warning(
|
|
24
20
|
"Insecure configuration. Use root level etc folder. "
|
edc_auth/urls_for_accounts.py
CHANGED
|
@@ -25,9 +25,7 @@ if allow_password_reset:
|
|
|
25
25
|
views.PasswordChangeDoneView.as_view(),
|
|
26
26
|
name="password_change_done",
|
|
27
27
|
),
|
|
28
|
-
path(
|
|
29
|
-
"password_reset/", views.PasswordResetView.as_view(), name="password_reset"
|
|
30
|
-
),
|
|
28
|
+
path("password_reset/", views.PasswordResetView.as_view(), name="password_reset"),
|
|
31
29
|
path(
|
|
32
30
|
"password_reset/done/",
|
|
33
31
|
views.PasswordResetDoneView.as_view(),
|
edc_auth/utils.py
CHANGED
|
@@ -24,9 +24,7 @@ def get_user(username: str) -> User | None:
|
|
|
24
24
|
return user
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
def compare_codenames_for_group(
|
|
28
|
-
group_name: str = None, expected: list[str] = None
|
|
29
|
-
) -> None:
|
|
27
|
+
def compare_codenames_for_group(group_name: str = None, expected: list[str] = None) -> None:
|
|
30
28
|
group = django_apps.get_model("auth.group").objects.get(name=group_name)
|
|
31
29
|
codenames = [p.codename for p in group.permissions.all()]
|
|
32
30
|
new_expected = []
|
|
@@ -47,9 +45,7 @@ def compare_codenames_for_group(
|
|
|
47
45
|
pprint(compared)
|
|
48
46
|
|
|
49
47
|
|
|
50
|
-
def remove_default_model_permissions_from_edc_permissions(
|
|
51
|
-
auth_updater: Any, app_label: str
|
|
52
|
-
):
|
|
48
|
+
def remove_default_model_permissions_from_edc_permissions(auth_updater: Any, app_label: str):
|
|
53
49
|
for group in auth_updater.group_model_cls.objects.all():
|
|
54
50
|
auth_updater.remove_permissions_by_codenames(
|
|
55
51
|
group=group,
|
|
@@ -121,9 +117,7 @@ def get_codenames_for_user(
|
|
|
121
117
|
roles = roles or user.userprofile.roles
|
|
122
118
|
|
|
123
119
|
for role in roles.all():
|
|
124
|
-
groups.extend(
|
|
125
|
-
[grp for grp in role.groups.all() if grp not in account_manager_groups]
|
|
126
|
-
)
|
|
120
|
+
groups.extend([grp for grp in role.groups.all() if grp not in account_manager_groups])
|
|
127
121
|
if include_groups:
|
|
128
122
|
for group in user.groups.all():
|
|
129
123
|
if group not in account_manager_groups:
|
edc_consent/actions.py
CHANGED
|
@@ -10,9 +10,7 @@ def verify_consent(request=None, consent_obj=None):
|
|
|
10
10
|
consent_obj.is_verified = True
|
|
11
11
|
consent_obj.is_verified_datetime = get_utcnow()
|
|
12
12
|
consent_obj.verified_by = request.user.username
|
|
13
|
-
consent_obj.save(
|
|
14
|
-
update_fields=["is_verified", "is_verified_datetime", "verified_by"]
|
|
15
|
-
)
|
|
13
|
+
consent_obj.save(update_fields=["is_verified", "is_verified_datetime", "verified_by"])
|
|
16
14
|
return consent_obj
|
|
17
15
|
|
|
18
16
|
|
|
@@ -20,9 +18,7 @@ def unverify_consent(consent_obj=None):
|
|
|
20
18
|
consent_obj.is_verified = False
|
|
21
19
|
consent_obj.is_verified_datetime = None
|
|
22
20
|
consent_obj.verified_by = None
|
|
23
|
-
consent_obj.save(
|
|
24
|
-
update_fields=["is_verified", "is_verified_datetime", "verified_by"]
|
|
25
|
-
)
|
|
21
|
+
consent_obj.save(update_fields=["is_verified", "is_verified_datetime", "verified_by"])
|
|
26
22
|
return consent_obj
|
|
27
23
|
|
|
28
24
|
|
|
@@ -48,9 +44,7 @@ def flag_as_verified_against_paper(modeladmin, request, queryset, **kwargs): #
|
|
|
48
44
|
)
|
|
49
45
|
|
|
50
46
|
|
|
51
|
-
flag_as_verified_against_paper.short_description =
|
|
52
|
-
"Verify consent against paper document"
|
|
53
|
-
)
|
|
47
|
+
flag_as_verified_against_paper.short_description = "Verify consent against paper document"
|
|
54
48
|
|
|
55
49
|
|
|
56
50
|
def unflag_as_verified_against_paper(modeladmin, request, queryset, **kwargs): # noqa
|
|
@@ -83,9 +83,7 @@ class ConsentDefinition:
|
|
|
83
83
|
if MALE not in self.gender and FEMALE not in self.gender:
|
|
84
84
|
raise ConsentDefinitionError(f"Invalid gender. Got {self.gender}.")
|
|
85
85
|
if not self.start.tzinfo:
|
|
86
|
-
raise ConsentDefinitionError(
|
|
87
|
-
f"Naive datetime not allowed. Got {self.start}."
|
|
88
|
-
)
|
|
86
|
+
raise ConsentDefinitionError(f"Naive datetime not allowed. Got {self.start}.")
|
|
89
87
|
elif str(self.start.tzinfo).upper() != "UTC":
|
|
90
88
|
raise ConsentDefinitionError(
|
|
91
89
|
f"Start date must be UTC. Got {self.start} / {self.start.tzinfo}."
|
|
@@ -141,9 +139,7 @@ class ConsentDefinition:
|
|
|
141
139
|
if self.country:
|
|
142
140
|
sites = site_sites.get_by_country(self.country, aslist=True)
|
|
143
141
|
elif self.site_ids:
|
|
144
|
-
sites = [
|
|
145
|
-
s for s in site_sites.all(aslist=True) if s.site_id in self.site_ids
|
|
146
|
-
]
|
|
142
|
+
sites = [s for s in site_sites.all(aslist=True) if s.site_id in self.site_ids]
|
|
147
143
|
else:
|
|
148
144
|
sites = [s for s in site_sites.all(aslist=True)]
|
|
149
145
|
return sites
|