clinicedc 2.0.6__py3-none-any.whl → 2.0.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of clinicedc might be problematic. Click here for more details.
- {clinicedc-2.0.6.dist-info → clinicedc-2.0.8.dist-info}/METADATA +2 -2
- {clinicedc-2.0.6.dist-info → clinicedc-2.0.8.dist-info}/RECORD +489 -441
- {clinicedc-2.0.6.dist-info → clinicedc-2.0.8.dist-info}/WHEEL +1 -1
- edc_action_item/action.py +1 -1
- edc_action_item/action_item_notification.py +2 -2
- edc_action_item/auths.py +37 -32
- edc_action_item/create_action_item.py +1 -1
- edc_action_item/decorators.py +1 -1
- edc_action_item/migrations/0001_initial.py +21 -22
- edc_action_item/migrations/0006_auto_20180707_1659.py +4 -4
- edc_action_item/migrations/0008_auto_20180809_0303.py +4 -4
- edc_action_item/migrations/0015_auto_20190114_0250.py +4 -4
- edc_action_item/migrations/0017_auto_20190305_0123.py +11 -30
- edc_action_item/migrations/0030_edcpermissions.py +3 -2
- edc_action_item/migrations/0039_alter_actionitem_auto_created_comment_and_more.py +398 -0
- edc_action_item/migrations/0040_alter_actionitem_report_datetime_and_more.py +34 -0
- edc_action_item/models/action_item.py +9 -4
- edc_action_item/models/action_model_mixin.py +5 -6
- edc_action_item/models/reference.py +2 -2
- edc_action_item/models/signals.py +22 -23
- edc_action_item/post_migrate_signals.py +1 -1
- edc_action_item/send_email.py +0 -85
- edc_action_item/site_action_items.py +5 -9
- edc_action_item/utils.py +3 -3
- edc_adherence/migrations/0005_alter_nonadherencereasons_extra_value_and_more.py +36 -0
- edc_adherence/model_mixins.py +1 -1
- edc_adverse_event/auths.py +55 -51
- edc_adverse_event/migrations/0001_initial.py +5 -4
- edc_adverse_event/migrations/0002_auto_20190802_0059.py +3 -2
- edc_adverse_event/migrations/0008_auto_20220825_0451.py +3 -2
- edc_adverse_event/migrations/0009_auto_20220907_0157.py +3 -2
- edc_adverse_event/migrations/0016_alter_aeactionclassification_device_created_and_more.py +285 -0
- edc_adverse_event/model_mixins/ae_followup/ae_followup_fields_model_mixin.py +2 -2
- edc_adverse_event/model_mixins/ae_initial/ae_initial_fields_model_mixin.py +6 -5
- edc_adverse_event/model_mixins/ae_special_interest/aesi_fields_model_mixin.py +2 -2
- edc_adverse_event/model_mixins/ae_susar/ae_susar_fields_model_mixin.py +2 -2
- edc_adverse_event/model_mixins/ae_tmg/ae_tmg_fields_model_mixin.py +15 -11
- edc_adverse_event/model_mixins/ae_tmg/ae_tmg_methods_model_mixin.py +2 -4
- edc_adverse_event/model_mixins/death_report/death_report_model_mixin.py +5 -4
- edc_adverse_event/model_mixins/death_report/death_report_tmg_model_mixin.py +6 -3
- edc_adverse_event/model_mixins/death_report/simple_death_report_model_mixin.py +2 -2
- edc_adverse_event/model_mixins/hospitaization/hospitalization_model_mixin.py +4 -3
- edc_adverse_event/modeladmin_mixins/death_report_admin_mixin.py +3 -3
- edc_adverse_event/models/signals.py +7 -7
- edc_adverse_event/templatetags/edc_adverse_event_extras.py +5 -4
- edc_adverse_event/view_mixins/ae/ae_listboard_view_mixin.py +3 -5
- edc_adverse_event/view_mixins/ae/death_report_listboard_view_mixin.py +6 -8
- edc_adverse_event/view_mixins/tmg/tmg_ae_listboard_view_mixin.py +2 -2
- edc_adverse_event/views/tmg/summary_listboard_view.py +3 -2
- edc_appointment/admin/appointment_admin.py +2 -2
- edc_appointment/admin/list_filters.py +2 -2
- edc_appointment/auths.py +14 -10
- edc_appointment/creators/appointment_creator.py +1 -1
- edc_appointment/creators/appointments_creator.py +1 -1
- edc_appointment/form_validators/appointment_form_validator.py +108 -82
- edc_appointment/migrations/0003_auto_20161127_2226.py +5 -6
- edc_appointment/migrations/0006_auto_20170106_2118.py +5 -5
- edc_appointment/migrations/0018_auto_20190305_0123.py +5 -12
- edc_appointment/migrations/0050_alter_appointment_appt_type_and_more.py +220 -0
- edc_appointment/model_mixins/appointment_fields_model_mixin.py +1 -2
- edc_appointment/model_mixins/appointment_methods_model_mixin.py +2 -3
- edc_appointment/model_mixins/appointment_model_mixin.py +31 -28
- edc_appointment/model_mixins/window_period_model_mixin.py +6 -7
- edc_appointment/models/appointment.py +1 -1
- edc_appointment/models/signals.py +44 -35
- edc_appointment/utils.py +19 -24
- edc_appointment/view_utils/appointment_button.py +2 -2
- edc_auth/admin/user_admin.py +1 -1
- edc_auth/auth_objects/__init__.py +2 -20
- edc_auth/auth_objects/default_groups.py +13 -11
- edc_auth/auth_objects/default_roles.py +26 -24
- edc_auth/auth_updater/auth_updater.py +13 -2
- edc_auth/auth_updater/group_updater.py +12 -10
- edc_auth/auth_updater/role_updater.py +2 -2
- edc_auth/constants.py +10 -0
- edc_auth/import_users.py +3 -3
- edc_auth/migrations/0001_squashed_0033_alter_userprofile_is_multisite_viewer.py +5 -5
- edc_auth/migrations/0012_auto_20191026_0034.py +3 -2
- edc_auth/migrations/0013_auto_20191026_0055.py +3 -2
- edc_auth/migrations/0025_permissions.py +3 -2
- edc_auth/migrations/0035_alter_edcpermissions_device_created_and_more.py +85 -0
- edc_auth/models/user_profile.py +14 -11
- edc_auth/post_migrate_signals.py +1 -1
- edc_auth/site_auths.py +80 -67
- edc_consent/actions.py +4 -5
- edc_consent/auths.py +18 -12
- edc_consent/migrations/0001_initial.py +3 -2
- edc_consent/migrations/0006_alter_edcpermissions_device_created_and_more.py +49 -0
- edc_consent/model_mixins/consent_extension_model_mixin.py +4 -5
- edc_consent/model_mixins/requires_consent_fields_model_mixin.py +2 -2
- edc_consent/utils.py +1 -1
- edc_constants/constants.py +1 -0
- edc_crf/auths.py +5 -0
- edc_crf/migrations/0001_initial.py +3 -2
- edc_crf/migrations/0009_alter_crfstatus_device_created_and_more.py +54 -0
- edc_dashboard/auths.py +10 -6
- edc_dashboard/migrations/0001_initial.py +3 -2
- edc_dashboard/migrations/0006_alter_edcpermissions_device_created_and_more.py +49 -0
- edc_dashboard/templatetags/edc_dashboard_extras.py +3 -2
- edc_dashboard/url_config.py +92 -83
- edc_dashboard/url_names.py +4 -4
- edc_dashboard/view_mixins/url_request_context_mixin.py +6 -5
- edc_data_manager/action_items.py +4 -6
- edc_data_manager/admin/actions.py +5 -5
- edc_data_manager/admin/data_query_admin.py +12 -11
- edc_data_manager/auths.py +37 -34
- edc_data_manager/handlers/handlers.py +6 -7
- edc_data_manager/migrations/0001_initial.py +19 -19
- edc_data_manager/migrations/0025_edcpermissions.py +3 -2
- edc_data_manager/migrations/0040_alter_datadictionary_device_created_and_more.py +327 -0
- edc_data_manager/migrations/0041_alter_dataquery_dm_user_and_more.py +164 -0
- edc_data_manager/models/data_query.py +5 -5
- edc_data_manager/models/model_mixins.py +8 -8
- edc_data_manager/rule/query_rule_wrapper.py +7 -7
- edc_data_manager/rule/rule_runner.py +4 -3
- edc_document_status/model_mixins.py +1 -1
- edc_egfr/egfr.py +11 -7
- edc_egfr/model_mixins/egfr_model_mixin.py +3 -7
- edc_export/admin/data_request_admin.py +2 -2
- edc_export/archive_exporter.py +7 -5
- edc_export/auths.py +32 -28
- edc_export/files_archiver.py +3 -2
- edc_export/migrations/0001_initial.py +26 -26
- edc_export/migrations/0004_auto_20190305_0123.py +25 -72
- edc_export/migrations/0013_edcpermissions.py +3 -2
- edc_export/migrations/0022_alter_datarequest_description_and_more.py +611 -0
- edc_export/migrations/0023_alter_datarequesthistory_archive_filename_and_more.py +29 -0
- edc_export/model_exporter/file_history_updater.py +10 -10
- edc_export/model_exporter/model_exporter.py +17 -15
- edc_export/model_exporter/object_history_helpers.py +2 -2
- edc_export/models/data_request_history.py +4 -4
- edc_export/utils.py +10 -15
- edc_facility/auths.py +8 -3
- edc_facility/facility.py +16 -22
- edc_facility/import_holidays.py +13 -13
- edc_facility/migrations/0005_healthfacility_healthfacilitytypes_and_more.py +8 -7
- edc_facility/migrations/0016_alter_healthfacility_device_created_and_more.py +139 -0
- edc_facility/migrations/0017_alter_healthfacility_gps_and_more.py +54 -0
- edc_facility/model_mixins.py +5 -5
- edc_form_label/custom_label_condition.py +11 -8
- edc_form_label/form_label.py +1 -1
- edc_form_runners/auths.py +11 -6
- edc_form_runners/form_runner.py +3 -5
- edc_form_runners/migrations/0001_initial.py +3 -2
- edc_form_runners/migrations/0005_alter_issue_device_created_and_more.py +49 -0
- edc_form_validators/applicable_field_validator.py +7 -6
- edc_form_validators/base_form_validator.py +8 -9
- edc_form_validators/other_specify_field_validator.py +2 -8
- edc_form_validators/required_field_validator.py +19 -16
- edc_identifier/migrations/0001_squashed_0018_auto_20180128_1054.py +3 -3
- edc_identifier/migrations/0002_auto_20190305_0123.py +3 -6
- edc_identifier/migrations/0006_auto_20161127_2226.py +15 -15
- edc_identifier/migrations/0007_auto_20161204_2227.py +3 -3
- edc_identifier/migrations/0009_auto_20161221_2323.py +3 -5
- edc_identifier/migrations/0010_auto_20170112_0602.py +17 -17
- edc_identifier/migrations/0011_alter_identifiermodel_device_created_and_more.py +79 -0
- edc_identifier/model_mixins.py +1 -1
- edc_identifier/models.py +9 -9
- edc_identifier/research_identifier.py +11 -10
- edc_identifier/simple_identifier.py +9 -5
- edc_identifier/subject_identifier.py +3 -2
- edc_lab/auths.py +26 -23
- edc_lab/lab/aliquot_creator.py +5 -8
- edc_lab/lab/primary_aliquot.py +14 -5
- edc_lab/migrations/0001_initial.py +29 -29
- edc_lab/migrations/0008_auto_20170921_0719.py +3 -3
- edc_lab/migrations/0010_auto_20171127_1541.py +15 -15
- edc_lab/migrations/0012_auto_20180114_1438.py +3 -3
- edc_lab/migrations/0019_auto_20190305_0123.py +43 -127
- edc_lab/migrations/0036_alter_aliquot_comment_alter_aliquot_device_created_and_more.py +1139 -0
- edc_lab/migrations/0037_alter_historicalorder_order_datetime_and_more.py +31 -0
- edc_lab/model_mixins/aliquot/aliquot_identifier_model_mixin.py +2 -2
- edc_lab/model_mixins/aliquot/aliquot_model_mixin.py +2 -2
- edc_lab/model_mixins/panel_model_mixin.py +18 -7
- edc_lab/model_mixins/requisition/crf_with_requisition_model_mixin.py +2 -4
- edc_lab/model_mixins/requisition/requisition_model_mixin.py +13 -16
- edc_lab/model_mixins/requisition/requisition_verify_model_mixin.py +1 -1
- edc_lab/model_mixins/result/result_item_model_mixin.py +4 -4
- edc_lab/model_mixins/shipping/manifest_model_mixin.py +4 -5
- edc_lab/model_mixins/shipping/verify_model_mixin.py +4 -6
- edc_lab/models/aliquot.py +2 -2
- edc_lab/models/box.py +1 -1
- edc_lab/models/box_item.py +6 -7
- edc_lab/models/manifest/manifest.py +3 -3
- edc_lab/models/manifest/manifest_item.py +7 -7
- edc_lab/models/manifest/shipper.py +3 -4
- edc_lab/models/order.py +6 -4
- edc_lab/models/panel.py +4 -4
- edc_lab/models/result.py +2 -2
- edc_lab/models/result_item.py +2 -2
- edc_lab_dashboard/auths.py +16 -11
- edc_lab_dashboard/migrations/0001_initial.py +3 -2
- edc_lab_dashboard/migrations/0005_alter_edcpermissions_device_created_and_more.py +49 -0
- edc_lab_dashboard/views/action_views/receive_view.py +2 -2
- edc_lab_dashboard/views/action_views/verify_box_item_view.py +2 -2
- edc_lab_results/calculate_missing.py +8 -8
- edc_lab_results/form_validator_mixins/blood_results_form_validator_mixin.py +2 -2
- edc_lab_results/get_summary.py +26 -25
- edc_lab_results/model_mixins/blood_result_model_mixin.py +9 -7
- edc_lab_results/model_mixins/fbg_model_mixin.py +3 -3
- edc_lab_results/model_mixins/glucose_model_mixin.py +3 -3
- edc_lab_results/model_mixins/hba1c_model_mixin.py +3 -3
- edc_label/auths.py +6 -1
- edc_label/label_template.py +8 -8
- edc_label/migrations/0001_initial.py +3 -2
- edc_label/migrations/0007_alter_zpllabeltemplates_device_created_and_more.py +49 -0
- edc_list_data/list_model_maker.py +2 -2
- edc_list_data/load_list_data.py +11 -14
- edc_list_data/load_model_data.py +3 -3
- edc_list_data/model_mixins.py +12 -4
- edc_list_data/post_migrate_signals.py +1 -1
- edc_list_data/preload_data.py +4 -4
- edc_list_data/row.py +1 -1
- edc_list_data/site_list_data.py +6 -5
- edc_listboard/migrations/0001_initial.py +3 -2
- edc_listboard/migrations/0007_alter_listboard_device_created_and_more.py +49 -0
- edc_locator/auths.py +18 -13
- edc_locator/migrations/0001_initial.py +7 -7
- edc_locator/migrations/0018_auto_20190305_0123.py +5 -12
- edc_locator/migrations/0040_alter_historicalsubjectlocator_action_identifier_and_more.py +187 -0
- edc_locator/migrations/0041_alter_historicalsubjectlocator_report_datetime_and_more.py +27 -0
- edc_locator/model_mixins/locator_model_mixin.py +2 -2
- edc_locator/model_mixins/subject_contact_fields_mixin.py +1 -1
- edc_locator/modeladmin_mixins.py +5 -4
- edc_ltfu/model_mixins.py +7 -5
- edc_metadata/auths.py +11 -7
- edc_metadata/metadata/metadata.py +1 -1
- edc_metadata/metadata_rules/crf/crf_rule.py +1 -1
- edc_metadata/metadata_rules/decorators.py +1 -1
- edc_metadata/metadata_rules/metadata_rule_evaluator.py +5 -3
- edc_metadata/metadata_rules/rule.py +2 -3
- edc_metadata/metadata_rules/rule_evaluator.py +1 -1
- edc_metadata/migrations/0002_auto_20161127_2226.py +5 -5
- edc_metadata/migrations/0005_auto_20170112_0602.py +5 -5
- edc_metadata/migrations/0011_auto_20190305_0123.py +5 -12
- edc_metadata/migrations/0031_alter_crfmetadata_device_created_and_more.py +120 -0
- edc_metadata/model_mixins/updates/updates_crf_metadata_model_mixin.py +7 -4
- edc_metadata/model_mixins/updates/updates_requisition_metadata_model_mixin.py +5 -2
- edc_metadata/models/crf_metadata.py +5 -5
- edc_metadata/models/crf_metadata_model_mixin.py +4 -5
- edc_metadata/models/requisition_metadata.py +6 -6
- edc_metadata/models/signals.py +10 -11
- edc_metadata/views/refresh_metadata_actions_view.py +3 -3
- edc_model/models/address_mixin.py +6 -6
- edc_model/models/fields/initials_field.py +2 -1
- edc_model/models/historical_records.py +2 -9
- edc_model/models/url_model_mixin.py +2 -2
- edc_model/validators/date.py +7 -8
- edc_model_admin/list_filters/future_date_list_filter.py +3 -3
- edc_model_admin/list_filters/past_date_list_filter.py +3 -3
- edc_model_admin/mixins/model_admin_protect_pii_mixin.py +4 -5
- edc_model_fields/fields/other_charfield.py +2 -2
- edc_navbar/auths.py +18 -13
- edc_navbar/migrations/0004_auto_20220825_0451.py +3 -2
- edc_navbar/migrations/0009_alter_edcpermissions_device_created_and_more.py +49 -0
- edc_notification/auths.py +9 -4
- edc_notification/migrations/0001_initial.py +3 -3
- edc_notification/migrations/0004_auto_20190305_0123.py +3 -6
- edc_notification/migrations/0011_alter_notification_device_created_and_more.py +59 -0
- edc_notification/models/notification.py +1 -1
- edc_notification/notification/graded_event_notification.py +2 -2
- edc_notification/notification/model_notification.py +3 -30
- edc_notification/notification/new_model_notification.py +1 -1
- edc_notification/notification/notification.py +12 -12
- edc_notification/notification/updated_model_notification.py +2 -2
- edc_offstudy/auths.py +12 -7
- edc_offstudy/migrations/0001_initial.py +4 -4
- edc_offstudy/migrations/0002_auto_20180921_0434.py +4 -4
- edc_offstudy/migrations/0005_auto_20190305_0123.py +5 -12
- edc_offstudy/migrations/0023_alter_historicalsubjectoffstudy_action_identifier_and_more.py +188 -0
- edc_offstudy/migrations/0024_alter_historicalsubjectoffstudy_offstudy_datetime_and_more.py +43 -0
- edc_offstudy/model_mixins/offstudy_model_mixin.py +3 -2
- edc_pdutils/df_exporters/csv_exporter.py +33 -37
- edc_pdutils/df_exporters/csv_model_exporter.py +7 -3
- edc_pdutils/migrations/0001_initial.py +8 -8
- edc_pharmacy/admin/prescription/rx_refill_admin.py +4 -3
- edc_pharmacy/admin/reports/stock_availability_admin.py +5 -6
- edc_pharmacy/auths.py +19 -15
- edc_pharmacy/migrations/0001_initial.py +64 -63
- edc_pharmacy/migrations/0015_auto_20220913_2139.py +26 -26
- edc_pharmacy/migrations/0024_allocation_assignment_containerunits_dispense_and_more.py +81 -86
- edc_pharmacy/migrations/0037_remove_historicalstock_confirmed_at_site_by_and_more.py +5 -5
- edc_pharmacy/migrations/0039_remove_dispense_registered_subject_and_more.py +7 -8
- edc_pharmacy/migrations/0049_remove_stocktransferconfirmation_stock_and_more.py +12 -12
- edc_pharmacy/migrations/0050_remove_stocktransferconfirmation2_location_and_more.py +5 -5
- edc_pharmacy/migrations/0051_alter_historicalstocktransferconfirmationitem_options_and_more.py +3 -4
- edc_pharmacy/migrations/0053_alter_location_managers_alter_historicalstock_lot_and_more.py +3 -3
- edc_pharmacy/migrations/0057_scanduplicates.py +3 -3
- edc_pharmacy/migrations/0060_alter_container_max_per_subject_and_more.py +13 -15
- edc_pharmacy/migrations/0068_stockout.py +2 -3
- edc_pharmacy/migrations/0076_historicalstockadjustment_stockadjustment.py +5 -5
- edc_pharmacy/migrations/0077_historicalstockadjustment_adjustment_datetime_and_more.py +3 -4
- edc_pharmacy/migrations/0081_historicalconfirmation_confirmation.py +8 -8
- edc_pharmacy/migrations/0084_confirmationatsiteitem_and_more.py +0 -2
- edc_pharmacy/migrations/0089_alter_allocation_allocated_by_and_more.py +3284 -0
- edc_pharmacy/migrations/0090_alter_allocation_allocation_datetime_and_more.py +227 -0
- edc_pharmacy/model_mixins/study_medication_refill_model_mixin.py +2 -2
- edc_pharmacy/models/medication/formulation.py +5 -7
- edc_pharmacy/models/medication/medication.py +3 -3
- edc_pharmacy/models/model_mixins.py +10 -11
- edc_pharmacy/models/prescription/rx.py +13 -12
- edc_pharmacy/models/prescription/rx_refill.py +0 -1
- edc_pharmacy/models/stock/allocation.py +3 -3
- edc_pharmacy/models/stock/confirmation.py +3 -3
- edc_pharmacy/models/stock/confirmation_at_site.py +3 -2
- edc_pharmacy/models/stock/confirmation_at_site_item.py +3 -4
- edc_pharmacy/models/stock/dispense.py +5 -6
- edc_pharmacy/models/stock/dispense_item.py +2 -2
- edc_pharmacy/models/stock/location.py +3 -4
- edc_pharmacy/models/stock/lot.py +6 -7
- edc_pharmacy/models/stock/order.py +1 -1
- edc_pharmacy/models/stock/receive.py +3 -3
- edc_pharmacy/models/stock/receive_item.py +4 -4
- edc_pharmacy/models/stock/repack_request.py +2 -2
- edc_pharmacy/models/stock/stock.py +12 -18
- edc_pharmacy/models/stock/stock_adjustment.py +4 -4
- edc_pharmacy/models/stock/stock_request.py +2 -2
- edc_pharmacy/models/stock/stock_request_item.py +2 -2
- edc_pharmacy/models/stock/stock_transfer.py +3 -3
- edc_pharmacy/models/stock/stock_transfer_item.py +2 -2
- edc_pharmacy/models/stock/storage_bin.py +3 -4
- edc_pharmacy/models/stock/storage_bin_item.py +2 -2
- edc_pharmacy/models/stock/supplier.py +3 -4
- edc_pharmacy/models/storage/box.py +2 -2
- edc_pharmacy/models/storage/items/container_model_mixin.py +3 -4
- edc_pharmacy/models/storage/items/pill_bottle_model_mixin.py +2 -2
- edc_pharmacy/models/storage/items/subject_pill_bottle.py +1 -1
- edc_pharmacy/models/storage/room.py +2 -2
- edc_pharmacy/models/storage/shelf.py +2 -2
- edc_pharmacy/models/storage/utils.py +1 -1
- edc_pharmacy/prescribe/create_prescription.py +3 -3
- edc_pharmacy/utils/allocate_stock.py +2 -3
- edc_pharmacy/utils/confirm_stock.py +3 -4
- edc_pharmacy/utils/confirm_stock_at_site.py +4 -5
- edc_pharmacy/utils/dispense.py +3 -4
- edc_pharmacy/utils/process_repack_request.py +4 -5
- edc_pharmacy/utils/stock_request/bulk_create_stock_request_items.py +2 -3
- edc_pharmacy/utils/transfer_stock.py +2 -3
- edc_pharmacy/views/add_to_storage_bin_view.py +2 -2
- edc_pharmacy/views/allocate_to_subject_view.py +2 -2
- edc_pharmacy/views/confirmation_at_site_view.py +6 -9
- edc_pharmacy/views/dispense_view.py +2 -2
- edc_pharmacy/views/move_to_storage_bin_view.py +2 -3
- edc_pharmacy/views/print_labels_view.py +2 -2
- edc_prn/admin_site.py +5 -0
- edc_prn/prn.py +10 -11
- edc_prn/urls.py +11 -0
- edc_protocol/research_protocol_config.py +2 -3
- edc_protocol_incident/action_items.py +4 -4
- edc_protocol_incident/auths.py +27 -20
- edc_protocol_incident/migrations/0001_initial.py +7 -7
- edc_protocol_incident/migrations/0001_squashed_0015_auto_20220927_0401.py +13 -13
- edc_protocol_incident/migrations/0005_protocolincident_historicalprotocolincident_and_more.py +7 -7
- edc_protocol_incident/migrations/0024_alter_actionsrequired_extra_value_and_more.py +625 -0
- edc_protocol_incident/migrations/0025_alter_historicalprotocoldeviationviolation_report_datetime_and_more.py +42 -0
- edc_protocol_incident/model_mixins/protocol_deviation_violation_model_mixin.py +18 -11
- edc_protocol_incident/model_mixins/protocol_incident_model_mixin.py +26 -11
- edc_pylabels/actions.py +3 -5
- edc_pylabels/auths.py +6 -1
- edc_pylabels/migrations/0002_alter_label_options_label_created_and_more.py +3 -7
- edc_pylabels/migrations/0005_labelconfiguration_delete_label_and_more.py +3 -3
- edc_pylabels/migrations/0013_alter_labelconfiguration_device_created_and_more.py +49 -0
- edc_qareports/auths.py +11 -7
- edc_qareports/migrations/0001_initial.py +4 -5
- edc_qareports/migrations/0005_edcpermissions.py +3 -3
- edc_qareports/migrations/0006_qareportlog.py +2 -3
- edc_qareports/migrations/0019_alter_edcpermissions_device_created_and_more.py +102 -0
- edc_qareports/migrations/0020_alter_note_report_datetime_and_more.py +24 -0
- edc_qareports/model_mixins/note_model_mixin.py +7 -4
- edc_qareports/model_mixins/on_study_missing_values_model_mixin.py +4 -4
- edc_qareports/model_mixins/qa_report_model_mixin.py +2 -3
- edc_qareports/models/note.py +4 -4
- edc_qareports/models/qa_reports_log.py +2 -3
- edc_randomization/admin.py +30 -24
- edc_randomization/auths.py +12 -7
- edc_randomization/decorators.py +1 -1
- edc_randomization/migrations/0001_initial.py +3 -2
- edc_randomization/migrations/0002_historicalrandomizationlist.py +3 -2
- edc_randomization/migrations/0009_edcpermissions.py +3 -2
- edc_randomization/migrations/0014_alter_edcpermissions_device_created_and_more.py +141 -0
- edc_randomization/model_mixins.py +9 -9
- edc_randomization/randomizer.py +22 -20
- edc_randomization/utils.py +19 -18
- edc_refusal/auths.py +7 -2
- edc_refusal/migrations/0001_initial.py +4 -4
- edc_refusal/migrations/0002_historicalsubjectrefusal.py +4 -4
- edc_refusal/migrations/0012_alter_historicalsubjectrefusal_comment_and_more.py +122 -0
- edc_refusal/migrations/0013_alter_historicalsubjectrefusal_report_datetime_and_more.py +28 -0
- edc_refusal/model_mixins.py +4 -4
- edc_registration/auths.py +28 -23
- edc_registration/migrations/0002_auto_20161127_2226.py +3 -4
- edc_registration/migrations/0005_auto_20170111_1809.py +4 -2
- edc_registration/migrations/0016_historicalregisteredsubject.py +3 -2
- edc_registration/migrations/0017_auto_20190305_0123.py +5 -12
- edc_registration/migrations/0033_alter_historicalregisteredsubject_additional_key_and_more.py +302 -0
- edc_registration/model_mixins/updates_or_creates_registered_subject_model_mixin.py +15 -7
- edc_registration/models/registered_subject.py +28 -27
- edc_reportable/age_evaluator.py +4 -2
- edc_reportable/formula.py +5 -5
- edc_reportable/migrations/0001_initial.py +7 -7
- edc_reportable/migrations/0003_referencerangecollection_grade1_and_more.py +3 -3
- edc_reportable/migrations/0004_alter_referencerangecollection_grade3_and_more.py +5 -5
- edc_reportable/migrations/0006_alter_gradingdata_revision_and_more.py +5 -6
- edc_reportable/migrations/0007_alter_gradingdata_age_phrase_and_more.py +509 -0
- edc_reportable/models/normal_data.py +4 -5
- edc_reportable/models/reference_model_mixins.py +10 -11
- edc_reportable/models/reference_range_collection.py +12 -13
- edc_reportable/post_migrate_signals.py +1 -1
- edc_reportable/utils/convert_units.py +11 -45
- edc_reportable/utils/get_normal_data_or_raise.py +2 -2
- edc_reportable/utils/get_reference_range_collection.py +2 -3
- edc_reportable/utils/load_data.py +4 -4
- edc_reportable/utils/update_grading_data.py +5 -5
- edc_review_dashboard/auths.py +23 -18
- edc_review_dashboard/migrations/0001_initial.py +3 -2
- edc_review_dashboard/migrations/0006_alter_edcpermissions_device_created_and_more.py +49 -0
- edc_screening/age_evaluator.py +6 -6
- edc_screening/auths.py +35 -30
- edc_screening/eligibility.py +1 -1
- edc_screening/gender_evaluator.py +1 -1
- edc_screening/migrations/0001_initial.py +3 -2
- edc_screening/migrations/0005_alter_edcpermissions_device_created_and_more.py +49 -0
- edc_screening/model_mixins/eligibility_model_mixin.py +3 -6
- edc_screening/model_mixins/screening_fields_model_mixin.py +6 -8
- edc_screening/model_mixins/screening_methods_model_mixin.py +1 -1
- edc_screening/screening_eligibility.py +2 -4
- edc_screening/utils.py +9 -9
- edc_search/generate_slug.py +26 -0
- edc_search/model_mixins.py +10 -22
- edc_sites/auths.py +8 -3
- edc_sites/migrations/0007_edcpermissions.py +3 -2
- edc_sites/migrations/0010_alter_edcpermissions_device_created_and_more.py +69 -0
- edc_sites/model_mixins/site_model_mixin.py +2 -2
- edc_sites/site.py +5 -5
- edc_sites/system_checks.py +1 -1
- edc_subject_dashboard/auths.py +27 -22
- edc_subject_dashboard/migrations/0001_initial.py +3 -2
- edc_subject_dashboard/migrations/0005_alter_edcpermissions_device_created_and_more.py +49 -0
- edc_subject_dashboard/requisition_report.py +6 -4
- edc_subject_dashboard/requisition_verifier.py +6 -6
- edc_subject_dashboard/templatetags/edc_subject_dashboard_extras.py +2 -2
- edc_subject_dashboard/view_mixins/subject_visit_view_mixin.py +7 -8
- edc_subject_dashboard/view_utils/subject_consent_listboard_button.py +3 -2
- edc_subject_dashboard/view_utils/timepoint_status_button.py +2 -2
- edc_timepoint/apps.py +0 -21
- edc_timepoint/model_mixins.py +22 -20
- edc_transfer/model_mixins.py +4 -4
- edc_transfer/modeladmin_mixins.py +1 -1
- edc_unblinding/auths.py +9 -4
- edc_unblinding/migrations/0001_initial.py +13 -13
- edc_unblinding/migrations/0014_alter_historicalunblindingrequest_action_identifier_and_more.py +291 -0
- edc_unblinding/migrations/0015_alter_historicalunblindingrequest_report_datetime_and_more.py +45 -0
- edc_unblinding/models/unblinding_request.py +2 -2
- edc_unblinding/models/unblinding_review.py +3 -3
- edc_utils/__init__.py +3 -1
- edc_utils/age.py +10 -16
- edc_utils/show_urls.py +29 -2
- edc_visit_schedule/auths.py +6 -1
- edc_visit_schedule/migrations/0001_initial.py +3 -3
- edc_visit_schedule/migrations/0002_auto_20190305_0123.py +3 -6
- edc_visit_schedule/migrations/0003_historicalvisitschedule_visitschedule.py +5 -4
- edc_visit_schedule/migrations/0015_historicalonschedule_offschedule_onschedule.py +10 -10
- edc_visit_schedule/migrations/0019_alter_historicalonschedule_device_created_and_more.py +229 -0
- edc_visit_schedule/migrations/0020_alter_historicalonschedule_onschedule_datetime_and_more.py +65 -0
- edc_visit_schedule/model_mixins/off_schedule_model_mixin.py +5 -4
- edc_visit_schedule/model_mixins/on_schedule_model_mixin.py +5 -4
- edc_visit_schedule/model_mixins/visit_schedule/visit_code_fields_model_mixin.py +1 -1
- edc_visit_schedule/models/subject_schedule_history.py +6 -6
- edc_visit_schedule/schedule/visit_collection.py +1 -1
- edc_visit_schedule/site_visit_schedules.py +2 -2
- edc_visit_schedule/subject_schedule.py +5 -4
- edc_visit_schedule/view_mixins.py +2 -3
- edc_visit_schedule/visit/visit.py +3 -2
- edc_visit_tracking/migrations/0004_subjectvisit_subjectvisitmissedreasons_extra_value_and_more.py +13 -13
- edc_visit_tracking/migrations/0009_alter_historicalsubjectvisit_comments_and_more.py +450 -0
- edc_visit_tracking/migrations/0010_alter_historicalsubjectvisit_report_datetime_and_more.py +68 -0
- edc_visit_tracking/model_mixins/base/visit_methods_model_mixin.py +3 -3
- edc_visit_tracking/model_mixins/crfs/visit_tracking_crf_model_mixin.py +2 -2
- edc_visit_tracking/model_mixins/requisitions/visit_tracking_requisition_model_mixin.py +2 -2
- edc_visit_tracking/model_mixins/subject_visit_missed_model_mixin.py +2 -2
- edc_visit_tracking/model_mixins/visit_model_mixin/caretaker_fields_mixin.py +2 -3
- edc_visit_tracking/model_mixins/visit_model_mixin/previous_visit_model_mixin.py +1 -1
- edc_visit_tracking/model_mixins/visit_model_mixin/visit_model_fields_mixin.py +8 -11
- edc_visit_tracking/model_mixins/visit_model_mixin/visit_model_mixin.py +1 -1
- edc_visit_tracking/models/signals.py +3 -3
- edc_visit_tracking/models/subject_visit.py +1 -1
- edc_vitals/calculators/bmi.py +7 -5
- edc_vitals/utils.py +1 -1
- edc_form_label/models.py +0 -0
- edc_search/constants.py +0 -1
- edc_search/models.py +0 -0
- edc_search/search_slug.py +0 -50
- edc_search/updater.py +0 -30
- edc_search/wsgi.py +0 -7
- {clinicedc-2.0.6.dist-info → clinicedc-2.0.8.dist-info}/licenses/LICENSE +0 -0
edc_qareports/models/note.py
CHANGED
|
@@ -21,11 +21,11 @@ class Note(NonUniqueSubjectIdentifierFieldMixin, NoteModelMixin):
|
|
|
21
21
|
class Meta(BaseUuidModel.Meta):
|
|
22
22
|
verbose_name = "Note"
|
|
23
23
|
verbose_name_plural = "Notes"
|
|
24
|
-
constraints =
|
|
24
|
+
constraints = (
|
|
25
25
|
UniqueConstraint(
|
|
26
26
|
fields=["report_model", "subject_identifier"],
|
|
27
27
|
name="%(app_label)s_%(class)s_report_model_subj_uniq",
|
|
28
|
-
)
|
|
29
|
-
|
|
28
|
+
),
|
|
29
|
+
)
|
|
30
30
|
indexes = BaseUuidModel.Meta.indexes
|
|
31
|
-
default_permissions = default_permissions
|
|
31
|
+
default_permissions = *default_permissions, "viewallsites"
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from django.contrib.sites.models import Site
|
|
2
2
|
from django.db import models
|
|
3
|
-
|
|
4
|
-
from edc_utils import get_utcnow
|
|
3
|
+
from django.utils import timezone
|
|
5
4
|
|
|
6
5
|
from ..model_mixins import qa_reports_permissions
|
|
7
6
|
|
|
@@ -10,7 +9,7 @@ class QaReportLog(models.Model):
|
|
|
10
9
|
username = models.CharField(max_length=100)
|
|
11
10
|
site = models.ForeignKey(Site, on_delete=models.CASCADE)
|
|
12
11
|
report_model = models.CharField(max_length=100)
|
|
13
|
-
accessed = models.DateTimeField(default=
|
|
12
|
+
accessed = models.DateTimeField(default=timezone.now)
|
|
14
13
|
|
|
15
14
|
class Meta:
|
|
16
15
|
verbose_name = "QA Report Log"
|
edc_randomization/admin.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import contextlib
|
|
2
|
+
|
|
1
3
|
from django.conf import settings
|
|
2
4
|
from django.contrib import admin
|
|
3
5
|
from django.contrib.admin.sites import AlreadyRegistered
|
|
@@ -65,7 +67,8 @@ class RandomizationListModelAdmin(TemplatesModelAdminMixin, admin.ModelAdmin):
|
|
|
65
67
|
|
|
66
68
|
def get_readonly_fields(self, request, obj=None):
|
|
67
69
|
readonly_fields = super().get_readonly_fields(request, obj=obj)
|
|
68
|
-
readonly_fields
|
|
70
|
+
readonly_fields = (
|
|
71
|
+
*readonly_fields,
|
|
69
72
|
"subject_identifier",
|
|
70
73
|
"sid",
|
|
71
74
|
"site_name",
|
|
@@ -75,7 +78,8 @@ class RandomizationListModelAdmin(TemplatesModelAdminMixin, admin.ModelAdmin):
|
|
|
75
78
|
"allocated_datetime",
|
|
76
79
|
"allocated_site",
|
|
77
80
|
"randomizer_name",
|
|
78
|
-
|
|
81
|
+
*audit_fields,
|
|
82
|
+
)
|
|
79
83
|
return tuple(set(readonly_fields))
|
|
80
84
|
|
|
81
85
|
def get_queryset(self, request):
|
|
@@ -90,7 +94,7 @@ class RandomizationListModelAdmin(TemplatesModelAdminMixin, admin.ModelAdmin):
|
|
|
90
94
|
return qs
|
|
91
95
|
|
|
92
96
|
def get_list_display(self, request) -> tuple[str, ...]:
|
|
93
|
-
|
|
97
|
+
fields = (
|
|
94
98
|
"sid",
|
|
95
99
|
"assignment",
|
|
96
100
|
"site_name",
|
|
@@ -98,22 +102,24 @@ class RandomizationListModelAdmin(TemplatesModelAdminMixin, admin.ModelAdmin):
|
|
|
98
102
|
"allocated_datetime",
|
|
99
103
|
"allocated_site",
|
|
100
104
|
"randomizer_name",
|
|
101
|
-
|
|
105
|
+
)
|
|
106
|
+
if flds := site_randomizers.get_by_model(
|
|
107
|
+
self.model._meta.label_lower
|
|
108
|
+
).get_extra_list_display():
|
|
109
|
+
fields = list(fields)
|
|
110
|
+
for pos, fname in flds:
|
|
111
|
+
fields.insert(pos, fname)
|
|
112
|
+
fields = tuple(fields)
|
|
102
113
|
if user_is_blinded(request.user.username) or (
|
|
103
114
|
not user_is_blinded(request.user.username)
|
|
104
115
|
and RANDO_UNBLINDED not in [g.name for g in request.user.groups.all()]
|
|
105
116
|
):
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
self.model._meta.label_lower
|
|
109
|
-
).get_extra_list_display():
|
|
110
|
-
for pos, fldname in flds:
|
|
111
|
-
list_display.insert(pos, fldname)
|
|
112
|
-
return tuple(list_display)
|
|
117
|
+
fields = tuple([fname for fname in fields if fname != "assignment"])
|
|
118
|
+
return fields
|
|
113
119
|
|
|
114
120
|
@staticmethod
|
|
115
121
|
def get_fieldnames(request) -> tuple[str, ...]:
|
|
116
|
-
fields =
|
|
122
|
+
fields = (
|
|
117
123
|
"subject_identifier",
|
|
118
124
|
"sid",
|
|
119
125
|
"assignment",
|
|
@@ -122,33 +128,35 @@ class RandomizationListModelAdmin(TemplatesModelAdminMixin, admin.ModelAdmin):
|
|
|
122
128
|
"allocated_datetime",
|
|
123
129
|
"allocated_site",
|
|
124
130
|
"randomizer_name",
|
|
125
|
-
|
|
131
|
+
)
|
|
126
132
|
if user_is_blinded(request.user.username) or (
|
|
127
133
|
not user_is_blinded(request.user.username)
|
|
128
134
|
and RANDO_UNBLINDED not in [g.name for g in request.user.groups.all()]
|
|
129
135
|
):
|
|
130
|
-
fields
|
|
131
|
-
return
|
|
136
|
+
fields = tuple([fname for fname in fields if fname != "assignment"])
|
|
137
|
+
return fields
|
|
132
138
|
|
|
133
139
|
def get_list_filter(self, request) -> tuple[str, ...]:
|
|
134
|
-
|
|
140
|
+
fields = (
|
|
135
141
|
"assignment",
|
|
136
142
|
"allocated_datetime",
|
|
137
143
|
"allocated_site",
|
|
138
144
|
"site_name",
|
|
139
145
|
"randomizer_name",
|
|
140
|
-
|
|
146
|
+
)
|
|
141
147
|
if flds := site_randomizers.get_by_model(
|
|
142
148
|
self.model._meta.label_lower
|
|
143
149
|
).get_extra_list_filter():
|
|
144
|
-
|
|
145
|
-
|
|
150
|
+
fields = list(fields)
|
|
151
|
+
for pos, fname in flds:
|
|
152
|
+
fields.insert(pos, fname)
|
|
153
|
+
fields = tuple(fields)
|
|
146
154
|
if user_is_blinded(request.user.username) or (
|
|
147
155
|
not user_is_blinded(request.user.username)
|
|
148
156
|
and RANDO_UNBLINDED not in [g.name for g in request.user.groups.all()]
|
|
149
157
|
):
|
|
150
|
-
|
|
151
|
-
return
|
|
158
|
+
fields = tuple([fname for fname in fields if fname != "assignment"])
|
|
159
|
+
return fields
|
|
152
160
|
|
|
153
161
|
|
|
154
162
|
def register_admin():
|
|
@@ -156,10 +164,8 @@ def register_admin():
|
|
|
156
164
|
for randomizer_cls in site_randomizers._registry.values():
|
|
157
165
|
model = randomizer_cls.model_cls()
|
|
158
166
|
admin_cls = type(f"{model.__name__}ModelAdmin", (RandomizationListModelAdmin,), {})
|
|
159
|
-
|
|
167
|
+
with contextlib.suppress(AlreadyRegistered):
|
|
160
168
|
edc_randomization_admin.register(model, admin_cls)
|
|
161
|
-
except AlreadyRegistered:
|
|
162
|
-
pass
|
|
163
169
|
|
|
164
170
|
|
|
165
171
|
register_admin()
|
edc_randomization/auths.py
CHANGED
|
@@ -9,11 +9,16 @@ from .auth_objects import (
|
|
|
9
9
|
update_rando_group_permissions,
|
|
10
10
|
)
|
|
11
11
|
|
|
12
|
-
site_auths.add_post_update_func(
|
|
13
|
-
"edc_randomization", remove_default_model_permissions_from_edc_permissions
|
|
14
|
-
)
|
|
15
12
|
|
|
16
|
-
|
|
17
|
-
site_auths.
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
def update_site_auths() -> None:
|
|
14
|
+
site_auths.add_post_update_func(
|
|
15
|
+
"edc_randomization", remove_default_model_permissions_from_edc_permissions
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
site_auths.add_group(get_rando_permissions_codenames, name=RANDO_BLINDED, view_only=True)
|
|
19
|
+
site_auths.add_group(get_rando_permissions_codenames, name=RANDO_UNBLINDED, view_only=True)
|
|
20
|
+
site_auths.add_post_update_func("edc_randomization", update_rando_group_permissions)
|
|
21
|
+
site_auths.add_post_update_func("edc_randomization", make_randomizationlist_view_only)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
update_site_auths()
|
edc_randomization/decorators.py
CHANGED
|
@@ -12,6 +12,7 @@ import django_revision.revision_field
|
|
|
12
12
|
from django.db import migrations, models
|
|
13
13
|
|
|
14
14
|
import edc_sites.models
|
|
15
|
+
import django.utils.timezone
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
class Migration(migrations.Migration):
|
|
@@ -38,14 +39,14 @@ class Migration(migrations.Migration):
|
|
|
38
39
|
"created",
|
|
39
40
|
models.DateTimeField(
|
|
40
41
|
blank=True,
|
|
41
|
-
default=
|
|
42
|
+
default=django.utils.timezone.now,
|
|
42
43
|
),
|
|
43
44
|
),
|
|
44
45
|
(
|
|
45
46
|
"modified",
|
|
46
47
|
models.DateTimeField(
|
|
47
48
|
blank=True,
|
|
48
|
-
default=
|
|
49
|
+
default=django.utils.timezone.now,
|
|
49
50
|
),
|
|
50
51
|
),
|
|
51
52
|
(
|
|
@@ -13,6 +13,7 @@ import django_revision.revision_field
|
|
|
13
13
|
import simple_history.models
|
|
14
14
|
from django.conf import settings
|
|
15
15
|
from django.db import migrations, models
|
|
16
|
+
import django.utils.timezone
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
class Migration(migrations.Migration):
|
|
@@ -41,14 +42,14 @@ class Migration(migrations.Migration):
|
|
|
41
42
|
"created",
|
|
42
43
|
models.DateTimeField(
|
|
43
44
|
blank=True,
|
|
44
|
-
default=
|
|
45
|
+
default=django.utils.timezone.now,
|
|
45
46
|
),
|
|
46
47
|
),
|
|
47
48
|
(
|
|
48
49
|
"modified",
|
|
49
50
|
models.DateTimeField(
|
|
50
51
|
blank=True,
|
|
51
|
-
default=
|
|
52
|
+
default=django.utils.timezone.now,
|
|
52
53
|
),
|
|
53
54
|
),
|
|
54
55
|
(
|
|
@@ -7,6 +7,7 @@ import django_audit_fields.fields.uuid_auto_field
|
|
|
7
7
|
import django_audit_fields.models.audit_model_mixin
|
|
8
8
|
import django_revision.revision_field
|
|
9
9
|
from django.db import migrations, models
|
|
10
|
+
import django.utils.timezone
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
class Migration(migrations.Migration):
|
|
@@ -33,14 +34,14 @@ class Migration(migrations.Migration):
|
|
|
33
34
|
"created",
|
|
34
35
|
models.DateTimeField(
|
|
35
36
|
blank=True,
|
|
36
|
-
default=
|
|
37
|
+
default=django.utils.timezone.now,
|
|
37
38
|
),
|
|
38
39
|
),
|
|
39
40
|
(
|
|
40
41
|
"modified",
|
|
41
42
|
models.DateTimeField(
|
|
42
43
|
blank=True,
|
|
43
|
-
default=
|
|
44
|
+
default=django.utils.timezone.now,
|
|
44
45
|
),
|
|
45
46
|
),
|
|
46
47
|
(
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Generated by Django 5.2.6 on 2025-09-17 16:53
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
("edc_randomization", "0013_alter_edcpermissions_revision_and_more"),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AlterField(
|
|
14
|
+
model_name="edcpermissions",
|
|
15
|
+
name="device_created",
|
|
16
|
+
field=models.CharField(
|
|
17
|
+
blank=True, default="", max_length=10, verbose_name="Device created"
|
|
18
|
+
),
|
|
19
|
+
),
|
|
20
|
+
migrations.AlterField(
|
|
21
|
+
model_name="edcpermissions",
|
|
22
|
+
name="device_modified",
|
|
23
|
+
field=models.CharField(
|
|
24
|
+
blank=True, default="", max_length=10, verbose_name="Device modified"
|
|
25
|
+
),
|
|
26
|
+
),
|
|
27
|
+
migrations.AlterField(
|
|
28
|
+
model_name="edcpermissions",
|
|
29
|
+
name="locale_created",
|
|
30
|
+
field=models.CharField(
|
|
31
|
+
blank=True,
|
|
32
|
+
default="",
|
|
33
|
+
help_text="Auto-updated by Modeladmin",
|
|
34
|
+
max_length=10,
|
|
35
|
+
verbose_name="Locale created",
|
|
36
|
+
),
|
|
37
|
+
),
|
|
38
|
+
migrations.AlterField(
|
|
39
|
+
model_name="edcpermissions",
|
|
40
|
+
name="locale_modified",
|
|
41
|
+
field=models.CharField(
|
|
42
|
+
blank=True,
|
|
43
|
+
default="",
|
|
44
|
+
help_text="Auto-updated by Modeladmin",
|
|
45
|
+
max_length=10,
|
|
46
|
+
verbose_name="Locale modified",
|
|
47
|
+
),
|
|
48
|
+
),
|
|
49
|
+
migrations.AlterField(
|
|
50
|
+
model_name="historicalrandomizationlist",
|
|
51
|
+
name="allocated_user",
|
|
52
|
+
field=models.CharField(default="", max_length=50),
|
|
53
|
+
),
|
|
54
|
+
migrations.AlterField(
|
|
55
|
+
model_name="historicalrandomizationlist",
|
|
56
|
+
name="device_created",
|
|
57
|
+
field=models.CharField(
|
|
58
|
+
blank=True, default="", max_length=10, verbose_name="Device created"
|
|
59
|
+
),
|
|
60
|
+
),
|
|
61
|
+
migrations.AlterField(
|
|
62
|
+
model_name="historicalrandomizationlist",
|
|
63
|
+
name="device_modified",
|
|
64
|
+
field=models.CharField(
|
|
65
|
+
blank=True, default="", max_length=10, verbose_name="Device modified"
|
|
66
|
+
),
|
|
67
|
+
),
|
|
68
|
+
migrations.AlterField(
|
|
69
|
+
model_name="historicalrandomizationlist",
|
|
70
|
+
name="locale_created",
|
|
71
|
+
field=models.CharField(
|
|
72
|
+
blank=True,
|
|
73
|
+
default="",
|
|
74
|
+
help_text="Auto-updated by Modeladmin",
|
|
75
|
+
max_length=10,
|
|
76
|
+
verbose_name="Locale created",
|
|
77
|
+
),
|
|
78
|
+
),
|
|
79
|
+
migrations.AlterField(
|
|
80
|
+
model_name="historicalrandomizationlist",
|
|
81
|
+
name="locale_modified",
|
|
82
|
+
field=models.CharField(
|
|
83
|
+
blank=True,
|
|
84
|
+
default="",
|
|
85
|
+
help_text="Auto-updated by Modeladmin",
|
|
86
|
+
max_length=10,
|
|
87
|
+
verbose_name="Locale modified",
|
|
88
|
+
),
|
|
89
|
+
),
|
|
90
|
+
migrations.AlterField(
|
|
91
|
+
model_name="historicalrandomizationlist",
|
|
92
|
+
name="verified_user",
|
|
93
|
+
field=models.CharField(default="", max_length=50),
|
|
94
|
+
),
|
|
95
|
+
migrations.AlterField(
|
|
96
|
+
model_name="randomizationlist",
|
|
97
|
+
name="allocated_user",
|
|
98
|
+
field=models.CharField(default="", max_length=50),
|
|
99
|
+
),
|
|
100
|
+
migrations.AlterField(
|
|
101
|
+
model_name="randomizationlist",
|
|
102
|
+
name="device_created",
|
|
103
|
+
field=models.CharField(
|
|
104
|
+
blank=True, default="", max_length=10, verbose_name="Device created"
|
|
105
|
+
),
|
|
106
|
+
),
|
|
107
|
+
migrations.AlterField(
|
|
108
|
+
model_name="randomizationlist",
|
|
109
|
+
name="device_modified",
|
|
110
|
+
field=models.CharField(
|
|
111
|
+
blank=True, default="", max_length=10, verbose_name="Device modified"
|
|
112
|
+
),
|
|
113
|
+
),
|
|
114
|
+
migrations.AlterField(
|
|
115
|
+
model_name="randomizationlist",
|
|
116
|
+
name="locale_created",
|
|
117
|
+
field=models.CharField(
|
|
118
|
+
blank=True,
|
|
119
|
+
default="",
|
|
120
|
+
help_text="Auto-updated by Modeladmin",
|
|
121
|
+
max_length=10,
|
|
122
|
+
verbose_name="Locale created",
|
|
123
|
+
),
|
|
124
|
+
),
|
|
125
|
+
migrations.AlterField(
|
|
126
|
+
model_name="randomizationlist",
|
|
127
|
+
name="locale_modified",
|
|
128
|
+
field=models.CharField(
|
|
129
|
+
blank=True,
|
|
130
|
+
default="",
|
|
131
|
+
help_text="Auto-updated by Modeladmin",
|
|
132
|
+
max_length=10,
|
|
133
|
+
verbose_name="Locale modified",
|
|
134
|
+
),
|
|
135
|
+
),
|
|
136
|
+
migrations.AlterField(
|
|
137
|
+
model_name="randomizationlist",
|
|
138
|
+
name="verified_user",
|
|
139
|
+
field=models.CharField(default="", max_length=50),
|
|
140
|
+
),
|
|
141
|
+
]
|
|
@@ -34,7 +34,7 @@ class RandomizationListModelMixin(models.Model):
|
|
|
34
34
|
|
|
35
35
|
randomizer_name = models.CharField(max_length=50, default="default")
|
|
36
36
|
|
|
37
|
-
subject_identifier = models.CharField(
|
|
37
|
+
subject_identifier = models.CharField( # noqa: DJ001
|
|
38
38
|
verbose_name="Subject Identifier", max_length=50, null=True, unique=True
|
|
39
39
|
)
|
|
40
40
|
|
|
@@ -48,7 +48,7 @@ class RandomizationListModelMixin(models.Model):
|
|
|
48
48
|
|
|
49
49
|
allocated_datetime = models.DateTimeField(null=True)
|
|
50
50
|
|
|
51
|
-
allocated_user = models.CharField(max_length=50,
|
|
51
|
+
allocated_user = models.CharField(max_length=50, default="")
|
|
52
52
|
|
|
53
53
|
allocated_site = models.ForeignKey(
|
|
54
54
|
Site, null=True, on_delete=models.PROTECT, related_name="+"
|
|
@@ -58,7 +58,7 @@ class RandomizationListModelMixin(models.Model):
|
|
|
58
58
|
|
|
59
59
|
verified_datetime = models.DateTimeField(null=True)
|
|
60
60
|
|
|
61
|
-
verified_user = models.CharField(max_length=50,
|
|
61
|
+
verified_user = models.CharField(max_length=50, default="")
|
|
62
62
|
|
|
63
63
|
objects = RandomizationListManager()
|
|
64
64
|
|
|
@@ -74,14 +74,14 @@ class RandomizationListModelMixin(models.Model):
|
|
|
74
74
|
try:
|
|
75
75
|
self.assignment_description
|
|
76
76
|
except RandomizationError as e:
|
|
77
|
-
raise RandomizationListModelError(e)
|
|
77
|
+
raise RandomizationListModelError(e) from e
|
|
78
78
|
try:
|
|
79
79
|
Site.objects.get(name=self.site_name)
|
|
80
|
-
except ObjectDoesNotExist:
|
|
80
|
+
except ObjectDoesNotExist as e:
|
|
81
81
|
site_names = [obj.name for obj in Site.objects.all()]
|
|
82
82
|
raise RandomizationListModelError(
|
|
83
83
|
f"Invalid site name. Got {self.site_name}. Expected one of {site_names}."
|
|
84
|
-
)
|
|
84
|
+
) from e
|
|
85
85
|
super().save(*args, **kwargs)
|
|
86
86
|
|
|
87
87
|
@property
|
|
@@ -109,10 +109,10 @@ class RandomizationListModelMixin(models.Model):
|
|
|
109
109
|
|
|
110
110
|
class Meta:
|
|
111
111
|
abstract = True
|
|
112
|
-
constraints =
|
|
112
|
+
constraints = (
|
|
113
113
|
UniqueConstraint(
|
|
114
114
|
fields=["site_name", "sid"],
|
|
115
115
|
name="%(app_label)s_%(class)s_site_sid_uniq",
|
|
116
|
-
)
|
|
117
|
-
|
|
116
|
+
),
|
|
117
|
+
)
|
|
118
118
|
permissions = (("display_assignment", "Can display assignment"),)
|
edc_randomization/randomizer.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import contextlib
|
|
3
4
|
import warnings
|
|
4
5
|
from datetime import datetime
|
|
5
6
|
from pathlib import Path
|
|
@@ -8,6 +9,7 @@ from typing import TYPE_CHECKING, Any
|
|
|
8
9
|
from django.apps import apps as django_apps
|
|
9
10
|
from django.conf import settings
|
|
10
11
|
from django.core.exceptions import ObjectDoesNotExist, ValidationError
|
|
12
|
+
from django.db.models import Q
|
|
11
13
|
|
|
12
14
|
from edc_registration.utils import get_registered_subject_model_cls
|
|
13
15
|
|
|
@@ -25,15 +27,15 @@ if TYPE_CHECKING:
|
|
|
25
27
|
from edc_registration.models import RegisteredSubject
|
|
26
28
|
|
|
27
29
|
|
|
28
|
-
class InvalidAssignmentDescriptionMap(Exception):
|
|
30
|
+
class InvalidAssignmentDescriptionMap(Exception): # noqa: N818
|
|
29
31
|
pass
|
|
30
32
|
|
|
31
33
|
|
|
32
|
-
class RandomizationListFileNotFound(Exception):
|
|
34
|
+
class RandomizationListFileNotFound(Exception): # noqa: N818
|
|
33
35
|
pass
|
|
34
36
|
|
|
35
37
|
|
|
36
|
-
class RandomizationListNotLoaded(Exception):
|
|
38
|
+
class RandomizationListNotLoaded(Exception): # noqa: N818
|
|
37
39
|
pass
|
|
38
40
|
|
|
39
41
|
|
|
@@ -41,7 +43,7 @@ class RandomizationError(Exception):
|
|
|
41
43
|
pass
|
|
42
44
|
|
|
43
45
|
|
|
44
|
-
class AlreadyRandomized(ValidationError):
|
|
46
|
+
class AlreadyRandomized(ValidationError): # noqa: N818
|
|
45
47
|
pass
|
|
46
48
|
|
|
47
49
|
|
|
@@ -113,10 +115,10 @@ class Randomizer:
|
|
|
113
115
|
subject_identifier: str | None = None,
|
|
114
116
|
identifier_attr: str | None = None,
|
|
115
117
|
identifier_object_name: str | None = None,
|
|
116
|
-
report_datetime: datetime = None,
|
|
117
|
-
site: Any = None,
|
|
118
|
-
user: str = None,
|
|
119
|
-
**kwargs,
|
|
118
|
+
report_datetime: datetime | None = None,
|
|
119
|
+
site: Any | None = None,
|
|
120
|
+
user: str | None = None,
|
|
121
|
+
**kwargs, # noqa: ARG002
|
|
120
122
|
):
|
|
121
123
|
self._model_obj = None
|
|
122
124
|
self._registration_obj = None
|
|
@@ -208,8 +210,10 @@ class Randomizer:
|
|
|
208
210
|
@property
|
|
209
211
|
def sid(self):
|
|
210
212
|
"""Returns the SID."""
|
|
211
|
-
if self.model_obj.sid
|
|
212
|
-
raise RandomizationError(
|
|
213
|
+
if not self.model_obj.sid:
|
|
214
|
+
raise RandomizationError(
|
|
215
|
+
f"SID cannot be None. See {self.model_obj}. Got {self.model_obj.sid}"
|
|
216
|
+
)
|
|
213
217
|
return self.model_obj.sid
|
|
214
218
|
|
|
215
219
|
@property
|
|
@@ -233,7 +237,7 @@ class Randomizer:
|
|
|
233
237
|
if not self._model_obj:
|
|
234
238
|
try:
|
|
235
239
|
obj = self.model_cls().objects.get(**self.identifier_opts)
|
|
236
|
-
except ObjectDoesNotExist:
|
|
240
|
+
except ObjectDoesNotExist as e:
|
|
237
241
|
opts = dict(site_name=self.site.name, **self.extra_model_obj_options)
|
|
238
242
|
self._model_obj = (
|
|
239
243
|
self.model_cls()
|
|
@@ -245,7 +249,7 @@ class Randomizer:
|
|
|
245
249
|
fld_str = ", ".join([f"{k}=`{v}`" for k, v in opts.items()])
|
|
246
250
|
raise AllocationError(
|
|
247
251
|
f"Randomization failed. No additional SIDs available for {fld_str}."
|
|
248
|
-
)
|
|
252
|
+
) from e
|
|
249
253
|
else:
|
|
250
254
|
raise AlreadyRandomized(
|
|
251
255
|
f"{self.identifier_object_name.title()} already randomized. "
|
|
@@ -282,7 +286,7 @@ class Randomizer:
|
|
|
282
286
|
Called by `registration_obj`.
|
|
283
287
|
"""
|
|
284
288
|
return self.get_registration_model_cls().objects.get(
|
|
285
|
-
sid__isnull=True, **self.identifier_opts
|
|
289
|
+
(Q(sid__isnull=True) | Q(sid="")), **self.identifier_opts
|
|
286
290
|
)
|
|
287
291
|
|
|
288
292
|
@property
|
|
@@ -298,14 +302,14 @@ class Randomizer:
|
|
|
298
302
|
if not self._registration_obj:
|
|
299
303
|
try:
|
|
300
304
|
self._registration_obj = self.get_unallocated_registration_obj()
|
|
301
|
-
except ObjectDoesNotExist:
|
|
305
|
+
except ObjectDoesNotExist as e:
|
|
302
306
|
try:
|
|
303
307
|
obj = self.get_registration_model_cls().objects.get(**self.identifier_opts)
|
|
304
|
-
except ObjectDoesNotExist:
|
|
308
|
+
except ObjectDoesNotExist as e:
|
|
305
309
|
raise RandomizationError(
|
|
306
310
|
f"{self.identifier_object_name.title()} does not exist. "
|
|
307
311
|
f"Got {getattr(self, self.identifier_attr)}"
|
|
308
|
-
)
|
|
312
|
+
) from e
|
|
309
313
|
else:
|
|
310
314
|
raise AlreadyRandomized(
|
|
311
315
|
f"{self.identifier_object_name.title()} already randomized. "
|
|
@@ -313,7 +317,7 @@ class Randomizer:
|
|
|
313
317
|
f"Got {getattr(obj, self.identifier_attr)} "
|
|
314
318
|
f"SID={obj.sid}",
|
|
315
319
|
code=self.get_registration_model_cls()._meta.label_lower,
|
|
316
|
-
)
|
|
320
|
+
) from e
|
|
317
321
|
return self._registration_obj
|
|
318
322
|
|
|
319
323
|
@property
|
|
@@ -347,7 +351,7 @@ class Randomizer:
|
|
|
347
351
|
"Randomization list file not found. "
|
|
348
352
|
f"Got `{cls.get_randomizationlist_path()}`. See Randomizer {cls.name}."
|
|
349
353
|
)
|
|
350
|
-
|
|
354
|
+
with contextlib.suppress(RandomizationListAlreadyImported):
|
|
351
355
|
result = cls.importer_cls(
|
|
352
356
|
assignment_map=cls.assignment_map,
|
|
353
357
|
randomizationlist_path=cls.get_randomizationlist_path(),
|
|
@@ -356,8 +360,6 @@ class Randomizer:
|
|
|
356
360
|
extra_csv_fieldnames=cls.extra_csv_fieldnames,
|
|
357
361
|
**kwargs,
|
|
358
362
|
).import_list(**kwargs)
|
|
359
|
-
except RandomizationListAlreadyImported:
|
|
360
|
-
pass
|
|
361
363
|
return result
|
|
362
364
|
|
|
363
365
|
@classmethod
|