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
|
@@ -6,7 +6,7 @@ from django.db import migrations, models
|
|
|
6
6
|
|
|
7
7
|
import edc_model_fields.fields.hostname_modification_field
|
|
8
8
|
import edc_model_fields.fields.userfield
|
|
9
|
-
import
|
|
9
|
+
import django.utils.timezone
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class Migration(migrations.Migration):
|
|
@@ -16,7 +16,7 @@ class Migration(migrations.Migration):
|
|
|
16
16
|
migrations.AlterField(
|
|
17
17
|
model_name="crfmetadata",
|
|
18
18
|
name="created",
|
|
19
|
-
field=models.DateTimeField(blank=True, default=
|
|
19
|
+
field=models.DateTimeField(blank=True, default=django.utils.timezone.now),
|
|
20
20
|
),
|
|
21
21
|
migrations.AlterField(
|
|
22
22
|
model_name="crfmetadata",
|
|
@@ -40,7 +40,7 @@ class Migration(migrations.Migration):
|
|
|
40
40
|
migrations.AlterField(
|
|
41
41
|
model_name="crfmetadata",
|
|
42
42
|
name="modified",
|
|
43
|
-
field=models.DateTimeField(blank=True, default=
|
|
43
|
+
field=models.DateTimeField(blank=True, default=django.utils.timezone.now),
|
|
44
44
|
),
|
|
45
45
|
migrations.AlterField(
|
|
46
46
|
model_name="crfmetadata",
|
|
@@ -59,7 +59,7 @@ class Migration(migrations.Migration):
|
|
|
59
59
|
migrations.AlterField(
|
|
60
60
|
model_name="requisitionmetadata",
|
|
61
61
|
name="created",
|
|
62
|
-
field=models.DateTimeField(blank=True, default=
|
|
62
|
+
field=models.DateTimeField(blank=True, default=django.utils.timezone.now),
|
|
63
63
|
),
|
|
64
64
|
migrations.AlterField(
|
|
65
65
|
model_name="requisitionmetadata",
|
|
@@ -83,7 +83,7 @@ class Migration(migrations.Migration):
|
|
|
83
83
|
migrations.AlterField(
|
|
84
84
|
model_name="requisitionmetadata",
|
|
85
85
|
name="modified",
|
|
86
|
-
field=models.DateTimeField(blank=True, default=
|
|
86
|
+
field=models.DateTimeField(blank=True, default=django.utils.timezone.now),
|
|
87
87
|
),
|
|
88
88
|
migrations.AlterField(
|
|
89
89
|
model_name="requisitionmetadata",
|
|
@@ -4,6 +4,7 @@ import django_audit_fields.fields.hostname_modification_field
|
|
|
4
4
|
import django_audit_fields.fields.userfield
|
|
5
5
|
import django_audit_fields.models.audit_model_mixin
|
|
6
6
|
from django.db import migrations, models
|
|
7
|
+
import django.utils.timezone
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
class Migration(migrations.Migration):
|
|
@@ -13,9 +14,7 @@ class Migration(migrations.Migration):
|
|
|
13
14
|
migrations.AlterField(
|
|
14
15
|
model_name="crfmetadata",
|
|
15
16
|
name="created",
|
|
16
|
-
field=models.DateTimeField(
|
|
17
|
-
blank=True, default=django_audit_fields.models.audit_model_mixin.utcnow
|
|
18
|
-
),
|
|
17
|
+
field=models.DateTimeField(blank=True, default=django.utils.timezone.now),
|
|
19
18
|
),
|
|
20
19
|
migrations.AlterField(
|
|
21
20
|
model_name="crfmetadata",
|
|
@@ -29,9 +28,7 @@ class Migration(migrations.Migration):
|
|
|
29
28
|
migrations.AlterField(
|
|
30
29
|
model_name="crfmetadata",
|
|
31
30
|
name="modified",
|
|
32
|
-
field=models.DateTimeField(
|
|
33
|
-
blank=True, default=django_audit_fields.models.audit_model_mixin.utcnow
|
|
34
|
-
),
|
|
31
|
+
field=models.DateTimeField(blank=True, default=django.utils.timezone.now),
|
|
35
32
|
),
|
|
36
33
|
migrations.AlterField(
|
|
37
34
|
model_name="crfmetadata",
|
|
@@ -56,9 +53,7 @@ class Migration(migrations.Migration):
|
|
|
56
53
|
migrations.AlterField(
|
|
57
54
|
model_name="requisitionmetadata",
|
|
58
55
|
name="created",
|
|
59
|
-
field=models.DateTimeField(
|
|
60
|
-
blank=True, default=django_audit_fields.models.audit_model_mixin.utcnow
|
|
61
|
-
),
|
|
56
|
+
field=models.DateTimeField(blank=True, default=django.utils.timezone.now),
|
|
62
57
|
),
|
|
63
58
|
migrations.AlterField(
|
|
64
59
|
model_name="requisitionmetadata",
|
|
@@ -72,9 +67,7 @@ class Migration(migrations.Migration):
|
|
|
72
67
|
migrations.AlterField(
|
|
73
68
|
model_name="requisitionmetadata",
|
|
74
69
|
name="modified",
|
|
75
|
-
field=models.DateTimeField(
|
|
76
|
-
blank=True, default=django_audit_fields.models.audit_model_mixin.utcnow
|
|
77
|
-
),
|
|
70
|
+
field=models.DateTimeField(blank=True, default=django.utils.timezone.now),
|
|
78
71
|
),
|
|
79
72
|
migrations.AlterField(
|
|
80
73
|
model_name="requisitionmetadata",
|
|
@@ -0,0 +1,120 @@
|
|
|
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_metadata", "0030_alter_crfmetadata_revision_and_more"),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AlterField(
|
|
14
|
+
model_name="crfmetadata",
|
|
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="crfmetadata",
|
|
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="crfmetadata",
|
|
29
|
+
name="document_name",
|
|
30
|
+
field=models.CharField(default="", max_length=250, verbose_name="Document"),
|
|
31
|
+
),
|
|
32
|
+
migrations.AlterField(
|
|
33
|
+
model_name="crfmetadata",
|
|
34
|
+
name="document_user",
|
|
35
|
+
field=models.CharField(default="", max_length=50, verbose_name="User"),
|
|
36
|
+
),
|
|
37
|
+
migrations.AlterField(
|
|
38
|
+
model_name="crfmetadata",
|
|
39
|
+
name="entry_comment",
|
|
40
|
+
field=models.TextField(blank=True, default="", max_length=250),
|
|
41
|
+
),
|
|
42
|
+
migrations.AlterField(
|
|
43
|
+
model_name="crfmetadata",
|
|
44
|
+
name="locale_created",
|
|
45
|
+
field=models.CharField(
|
|
46
|
+
blank=True,
|
|
47
|
+
default="",
|
|
48
|
+
help_text="Auto-updated by Modeladmin",
|
|
49
|
+
max_length=10,
|
|
50
|
+
verbose_name="Locale created",
|
|
51
|
+
),
|
|
52
|
+
),
|
|
53
|
+
migrations.AlterField(
|
|
54
|
+
model_name="crfmetadata",
|
|
55
|
+
name="locale_modified",
|
|
56
|
+
field=models.CharField(
|
|
57
|
+
blank=True,
|
|
58
|
+
default="",
|
|
59
|
+
help_text="Auto-updated by Modeladmin",
|
|
60
|
+
max_length=10,
|
|
61
|
+
verbose_name="Locale modified",
|
|
62
|
+
),
|
|
63
|
+
),
|
|
64
|
+
migrations.AlterField(
|
|
65
|
+
model_name="requisitionmetadata",
|
|
66
|
+
name="device_created",
|
|
67
|
+
field=models.CharField(
|
|
68
|
+
blank=True, default="", max_length=10, verbose_name="Device created"
|
|
69
|
+
),
|
|
70
|
+
),
|
|
71
|
+
migrations.AlterField(
|
|
72
|
+
model_name="requisitionmetadata",
|
|
73
|
+
name="device_modified",
|
|
74
|
+
field=models.CharField(
|
|
75
|
+
blank=True, default="", max_length=10, verbose_name="Device modified"
|
|
76
|
+
),
|
|
77
|
+
),
|
|
78
|
+
migrations.AlterField(
|
|
79
|
+
model_name="requisitionmetadata",
|
|
80
|
+
name="document_name",
|
|
81
|
+
field=models.CharField(default="", max_length=250, verbose_name="Document"),
|
|
82
|
+
),
|
|
83
|
+
migrations.AlterField(
|
|
84
|
+
model_name="requisitionmetadata",
|
|
85
|
+
name="document_user",
|
|
86
|
+
field=models.CharField(default="", max_length=50, verbose_name="User"),
|
|
87
|
+
),
|
|
88
|
+
migrations.AlterField(
|
|
89
|
+
model_name="requisitionmetadata",
|
|
90
|
+
name="entry_comment",
|
|
91
|
+
field=models.TextField(blank=True, default="", max_length=250),
|
|
92
|
+
),
|
|
93
|
+
migrations.AlterField(
|
|
94
|
+
model_name="requisitionmetadata",
|
|
95
|
+
name="locale_created",
|
|
96
|
+
field=models.CharField(
|
|
97
|
+
blank=True,
|
|
98
|
+
default="",
|
|
99
|
+
help_text="Auto-updated by Modeladmin",
|
|
100
|
+
max_length=10,
|
|
101
|
+
verbose_name="Locale created",
|
|
102
|
+
),
|
|
103
|
+
),
|
|
104
|
+
migrations.AlterField(
|
|
105
|
+
model_name="requisitionmetadata",
|
|
106
|
+
name="locale_modified",
|
|
107
|
+
field=models.CharField(
|
|
108
|
+
blank=True,
|
|
109
|
+
default="",
|
|
110
|
+
help_text="Auto-updated by Modeladmin",
|
|
111
|
+
max_length=10,
|
|
112
|
+
verbose_name="Locale modified",
|
|
113
|
+
),
|
|
114
|
+
),
|
|
115
|
+
migrations.AlterField(
|
|
116
|
+
model_name="requisitionmetadata",
|
|
117
|
+
name="panel_name",
|
|
118
|
+
field=models.CharField(default="", max_length=50),
|
|
119
|
+
),
|
|
120
|
+
]
|
|
@@ -50,16 +50,19 @@ class UpdatesCrfMetadataModelMixin(UpdatesMetadataModelMixin):
|
|
|
50
50
|
return django_apps.get_model(metadata_model)
|
|
51
51
|
|
|
52
52
|
@property
|
|
53
|
-
def metadata_default_entry_status(self: CrfModel) -> str:
|
|
53
|
+
def metadata_default_entry_status(self: CrfModel) -> str | None:
|
|
54
54
|
"""Returns a string that represents the default entry status
|
|
55
55
|
of the CRF in the visit schedule.
|
|
56
56
|
"""
|
|
57
57
|
crfs_prn = self.metadata_visit_object.crfs_prn
|
|
58
58
|
if self.related_visit.visit_code_sequence != 0:
|
|
59
|
-
crfs = self.metadata_visit_object.crfs_unscheduled.forms
|
|
59
|
+
crfs = (*self.metadata_visit_object.crfs_unscheduled.forms, *crfs_prn.forms)
|
|
60
60
|
else:
|
|
61
|
-
crfs = self.metadata_visit_object.crfs.forms
|
|
62
|
-
|
|
61
|
+
crfs = (*self.metadata_visit_object.crfs.forms, *crfs_prn.forms)
|
|
62
|
+
try:
|
|
63
|
+
crf = next(c for c in crfs if c.model == self._meta.label_lower)
|
|
64
|
+
except StopIteration:
|
|
65
|
+
return None
|
|
63
66
|
return REQUIRED if crf.required else NOT_REQUIRED
|
|
64
67
|
|
|
65
68
|
class Meta:
|
|
@@ -50,7 +50,7 @@ class UpdatesRequisitionMetadataModelMixin(UpdatesMetadataModelMixin):
|
|
|
50
50
|
return options
|
|
51
51
|
|
|
52
52
|
@property
|
|
53
|
-
def metadata_default_entry_status(self: RequisitionModel) -> str:
|
|
53
|
+
def metadata_default_entry_status(self: RequisitionModel) -> str | None:
|
|
54
54
|
"""Returns a string that represents the configured
|
|
55
55
|
entry status of the requisition in the visit schedule.
|
|
56
56
|
"""
|
|
@@ -64,7 +64,10 @@ class UpdatesRequisitionMetadataModelMixin(UpdatesMetadataModelMixin):
|
|
|
64
64
|
requisitions = (
|
|
65
65
|
self.metadata_visit_object.requisitions.forms + requisitions_prn.forms
|
|
66
66
|
)
|
|
67
|
-
|
|
67
|
+
try:
|
|
68
|
+
requisition = next(r for r in requisitions if r.panel.name == self.panel.name)
|
|
69
|
+
except StopIteration:
|
|
70
|
+
return None
|
|
68
71
|
return REQUIRED if requisition.required else NOT_REQUIRED
|
|
69
72
|
|
|
70
73
|
@property
|
|
@@ -29,7 +29,7 @@ class CrfMetadata(CrfMetadataModelMixin, BaseUuidModel):
|
|
|
29
29
|
)
|
|
30
30
|
|
|
31
31
|
# noinspection PyTypeHints
|
|
32
|
-
natural_key.dependencies =
|
|
32
|
+
natural_key.dependencies = ("sites.Site",)
|
|
33
33
|
|
|
34
34
|
@property
|
|
35
35
|
def verbose_name(self) -> str:
|
|
@@ -42,8 +42,8 @@ class CrfMetadata(CrfMetadataModelMixin, BaseUuidModel):
|
|
|
42
42
|
class Meta(CrfMetadataModelMixin.Meta, BaseUuidModel.Meta):
|
|
43
43
|
verbose_name = "Crf collection status"
|
|
44
44
|
verbose_name_plural = "Crf collection status"
|
|
45
|
-
unique_together =
|
|
46
|
-
constraints =
|
|
45
|
+
unique_together = ()
|
|
46
|
+
constraints = (
|
|
47
47
|
UniqueConstraint(
|
|
48
48
|
fields=[
|
|
49
49
|
"subject_identifier",
|
|
@@ -54,8 +54,8 @@ class CrfMetadata(CrfMetadataModelMixin, BaseUuidModel):
|
|
|
54
54
|
"model",
|
|
55
55
|
],
|
|
56
56
|
name="%(app_label)s_%(class)s_subject_iden_visit_uniq",
|
|
57
|
-
)
|
|
58
|
-
|
|
57
|
+
),
|
|
58
|
+
)
|
|
59
59
|
indexes = (
|
|
60
60
|
*CrfMetadataModelMixin.Meta.indexes,
|
|
61
61
|
*BaseUuidModel.Meta.indexes,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import contextlib
|
|
3
4
|
from typing import TYPE_CHECKING, Any
|
|
4
5
|
|
|
5
6
|
from django.apps import apps as django_apps
|
|
@@ -38,7 +39,7 @@ class CrfMetadataModelMixin(
|
|
|
38
39
|
|
|
39
40
|
model = models.CharField(max_length=50)
|
|
40
41
|
|
|
41
|
-
document_name = models.CharField(verbose_name=_("Document"), max_length=250,
|
|
42
|
+
document_name = models.CharField(verbose_name=_("Document"), max_length=250, default="")
|
|
42
43
|
|
|
43
44
|
show_order = models.IntegerField() # must always be provided!
|
|
44
45
|
|
|
@@ -54,7 +55,7 @@ class CrfMetadataModelMixin(
|
|
|
54
55
|
|
|
55
56
|
fill_datetime = models.DateTimeField(null=True, blank=True)
|
|
56
57
|
|
|
57
|
-
document_user = models.CharField(verbose_name=_("User"), max_length=50,
|
|
58
|
+
document_user = models.CharField(verbose_name=_("User"), max_length=50, default="")
|
|
58
59
|
|
|
59
60
|
def natural_key(self):
|
|
60
61
|
return (
|
|
@@ -92,10 +93,8 @@ class CrfMetadataModelMixin(
|
|
|
92
93
|
def model_instance(self: Any) -> Any:
|
|
93
94
|
"""Returns the CRF/Requisition model instance or None"""
|
|
94
95
|
instance = None
|
|
95
|
-
|
|
96
|
+
with contextlib.suppress(ObjectDoesNotExist):
|
|
96
97
|
instance = self.model_cls.objects.get(**self.model_instance_query_opts())
|
|
97
|
-
except ObjectDoesNotExist:
|
|
98
|
-
pass
|
|
99
98
|
return instance
|
|
100
99
|
|
|
101
100
|
def refresh_entry_status(self) -> str:
|
|
@@ -10,7 +10,7 @@ from .crf_metadata_model_mixin import CrfMetadataModelMixin
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class RequisitionMetadata(CrfMetadataModelMixin, BaseUuidModel):
|
|
13
|
-
panel_name = models.CharField(max_length=50,
|
|
13
|
+
panel_name = models.CharField(max_length=50, default="")
|
|
14
14
|
|
|
15
15
|
objects = RequisitionMetadataManager()
|
|
16
16
|
|
|
@@ -26,7 +26,7 @@ class RequisitionMetadata(CrfMetadataModelMixin, BaseUuidModel):
|
|
|
26
26
|
|
|
27
27
|
@property
|
|
28
28
|
def verbose_name(self) -> str:
|
|
29
|
-
from edc_lab.site_labs import site_labs
|
|
29
|
+
from edc_lab.site_labs import site_labs # noqa: PLC0415
|
|
30
30
|
|
|
31
31
|
return site_labs.panel_names.get(self.panel_name) or self.panel_name
|
|
32
32
|
|
|
@@ -42,7 +42,7 @@ class RequisitionMetadata(CrfMetadataModelMixin, BaseUuidModel):
|
|
|
42
42
|
)
|
|
43
43
|
|
|
44
44
|
# noinspection PyTypeHints
|
|
45
|
-
natural_key.dependencies =
|
|
45
|
+
natural_key.dependencies = ("sites.Site",) # type: ignore
|
|
46
46
|
|
|
47
47
|
def model_instance_query_opts(self) -> dict:
|
|
48
48
|
opts = super().model_instance_query_opts()
|
|
@@ -71,7 +71,7 @@ class RequisitionMetadata(CrfMetadataModelMixin, BaseUuidModel):
|
|
|
71
71
|
app_label = "edc_metadata"
|
|
72
72
|
verbose_name = "Requisition collection status"
|
|
73
73
|
verbose_name_plural = "Requisition collection status"
|
|
74
|
-
constraints =
|
|
74
|
+
constraints = (
|
|
75
75
|
UniqueConstraint(
|
|
76
76
|
fields=[
|
|
77
77
|
"subject_identifier",
|
|
@@ -83,8 +83,8 @@ class RequisitionMetadata(CrfMetadataModelMixin, BaseUuidModel):
|
|
|
83
83
|
"panel_name",
|
|
84
84
|
],
|
|
85
85
|
name="%(app_label)s_%(class)s_subject_iden_visit_uniq",
|
|
86
|
-
)
|
|
87
|
-
|
|
86
|
+
),
|
|
87
|
+
)
|
|
88
88
|
indexes = (
|
|
89
89
|
*CrfMetadataModelMixin.Meta.indexes,
|
|
90
90
|
*BaseUuidModel.Meta.indexes,
|
edc_metadata/models/signals.py
CHANGED
|
@@ -94,14 +94,13 @@ def metadata_reset_on_post_delete(sender, instance, using, **kwargs) -> None:
|
|
|
94
94
|
def metadata_update_previous_timepoints_for_singleton_on_post_save(
|
|
95
95
|
sender, instance, raw, created, using, **kwargs
|
|
96
96
|
):
|
|
97
|
-
if
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
appointment = appointment.relative_previous_with_related_visit
|
|
97
|
+
if (
|
|
98
|
+
not raw
|
|
99
|
+
and not kwargs.get("update_fields")
|
|
100
|
+
and isinstance(instance, (SingletonCrfModelMixin,))
|
|
101
|
+
):
|
|
102
|
+
appointment = instance.related_visit.appointment.relative_previous_with_related_visit
|
|
103
|
+
while appointment:
|
|
104
|
+
if appointment.related_visit:
|
|
105
|
+
refresh_metadata_for_timepoint(appointment.related_visit, allow_create=False)
|
|
106
|
+
appointment = appointment.relative_previous_with_related_visit
|
|
@@ -3,11 +3,11 @@ from django.contrib.auth.mixins import LoginRequiredMixin
|
|
|
3
3
|
from django.contrib.messages import SUCCESS
|
|
4
4
|
from django.http.response import HttpResponseRedirect
|
|
5
5
|
from django.urls import reverse
|
|
6
|
+
from django.utils import timezone
|
|
6
7
|
from django.views import View
|
|
7
8
|
|
|
8
9
|
from edc_appointment.utils import update_appt_status_for_timepoint
|
|
9
10
|
from edc_dashboard.url_names import url_names
|
|
10
|
-
from edc_utils import get_utcnow
|
|
11
11
|
from edc_utils.round_up import round_half_away_from_zero
|
|
12
12
|
from edc_visit_tracking.utils import get_related_visit_model_cls
|
|
13
13
|
|
|
@@ -34,7 +34,7 @@ class RefreshMetadataActionsView(LoginRequiredMixin, View):
|
|
|
34
34
|
return related_visit
|
|
35
35
|
|
|
36
36
|
def get(self, request, *args, **kwargs):
|
|
37
|
-
dte1 =
|
|
37
|
+
dte1 = timezone.now()
|
|
38
38
|
related_visit = self.refresh_metadata_for_timepoint(**kwargs)
|
|
39
39
|
url_name = url_names.get("subject_dashboard_url")
|
|
40
40
|
args = (
|
|
@@ -47,7 +47,7 @@ class RefreshMetadataActionsView(LoginRequiredMixin, View):
|
|
|
47
47
|
SUCCESS,
|
|
48
48
|
f"The data collection schedule for {related_visit.visit_code}."
|
|
49
49
|
f"{related_visit.visit_code_sequence} has been refreshed "
|
|
50
|
-
f"({round_half_away_from_zero((
|
|
50
|
+
f"({round_half_away_from_zero((timezone.now() - dte1).microseconds / 1000000, 2)} "
|
|
51
51
|
"seconds)",
|
|
52
52
|
)
|
|
53
53
|
return HttpResponseRedirect(url)
|
|
@@ -2,7 +2,7 @@ from django.db import models
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
class AddressMixin(models.Model):
|
|
5
|
-
contact_name = models.CharField(max_length=50,
|
|
5
|
+
contact_name = models.CharField(max_length=50, default="", blank=True)
|
|
6
6
|
|
|
7
7
|
address = models.CharField(verbose_name="Address", max_length=50)
|
|
8
8
|
|
|
@@ -11,18 +11,18 @@ class AddressMixin(models.Model):
|
|
|
11
11
|
city = models.CharField(max_length=50)
|
|
12
12
|
|
|
13
13
|
state = models.CharField(
|
|
14
|
-
verbose_name="State or Province",
|
|
14
|
+
verbose_name="State or Province", default="", blank=True, max_length=50
|
|
15
15
|
)
|
|
16
16
|
|
|
17
17
|
country = models.CharField(max_length=50)
|
|
18
18
|
|
|
19
|
-
telephone = models.CharField(
|
|
19
|
+
telephone = models.CharField(default="", blank=True, max_length=50)
|
|
20
20
|
|
|
21
|
-
mobile = models.CharField(
|
|
21
|
+
mobile = models.CharField(default="", blank=True, max_length=50)
|
|
22
22
|
|
|
23
|
-
fax = models.CharField(
|
|
23
|
+
fax = models.CharField(default="", blank=True, max_length=50)
|
|
24
24
|
|
|
25
|
-
email = models.EmailField(
|
|
25
|
+
email = models.EmailField(default="", blank=True, max_length=50)
|
|
26
26
|
|
|
27
27
|
class Meta:
|
|
28
28
|
abstract = True
|
|
@@ -12,6 +12,7 @@ class InitialsField(CharField):
|
|
|
12
12
|
kwargs.setdefault("editable", True)
|
|
13
13
|
kwargs.setdefault("verbose_name", _("Initials"))
|
|
14
14
|
kwargs.setdefault("max_length", 3)
|
|
15
|
+
kwargs.setdefault("default", "")
|
|
15
16
|
kwargs.setdefault("help_text", _("Type 2-3 letters, all in uppercase and no spaces"))
|
|
16
17
|
CharField.__init__(self, *args, **kwargs)
|
|
17
18
|
|
|
@@ -31,4 +32,4 @@ class InitialsField(CharField):
|
|
|
31
32
|
},
|
|
32
33
|
}
|
|
33
34
|
defaults.update(kwargs)
|
|
34
|
-
return super(
|
|
35
|
+
return super().formfield(**defaults)
|
|
@@ -16,10 +16,7 @@ class SerializableModel(models.Model):
|
|
|
16
16
|
return (self.history_id,)
|
|
17
17
|
|
|
18
18
|
def related_visit_model_attr(self):
|
|
19
|
-
|
|
20
|
-
return self.history_object.related_visit_model_attr()
|
|
21
|
-
except AttributeError:
|
|
22
|
-
raise
|
|
19
|
+
return self.history_object.related_visit_model_attr()
|
|
23
20
|
|
|
24
21
|
@property
|
|
25
22
|
def related_visit(self):
|
|
@@ -61,10 +58,6 @@ class HistoricalRecords(SimpleHistoricalRecords):
|
|
|
61
58
|
super().__init__(**kwargs)
|
|
62
59
|
|
|
63
60
|
def contribute_to_class(self, cls, name):
|
|
64
|
-
|
|
65
|
-
cls.related_visit_model_attr
|
|
66
|
-
except AttributeError:
|
|
67
|
-
pass
|
|
68
|
-
else:
|
|
61
|
+
if getattr(cls, "related_visit_model_attr", None):
|
|
69
62
|
self.model_cls = SerializableCrfModel
|
|
70
63
|
return super().contribute_to_class(cls, name)
|
|
@@ -5,7 +5,7 @@ from django.urls import reverse
|
|
|
5
5
|
from django.urls.exceptions import NoReverseMatch
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
class UrlModelMixinNoReverseMatch(Exception):
|
|
8
|
+
class UrlModelMixinNoReverseMatch(Exception): # noqa: N818
|
|
9
9
|
pass
|
|
10
10
|
|
|
11
11
|
|
|
@@ -23,7 +23,7 @@ class UrlModelMixin(models.Model):
|
|
|
23
23
|
f"Tried {self.admin_url_name}. Got {e}. "
|
|
24
24
|
"Check urls and confirm app is in INSTALLED_APPS. If running tests, "
|
|
25
25
|
"you may need to set `use_test_urls=True`."
|
|
26
|
-
)
|
|
26
|
+
) from e
|
|
27
27
|
return absolute_url
|
|
28
28
|
|
|
29
29
|
def get_changelist_url(self, search_term=None) -> str:
|
edc_model/validators/date.py
CHANGED
|
@@ -1,37 +1,36 @@
|
|
|
1
1
|
from datetime import date, datetime, timedelta
|
|
2
2
|
|
|
3
3
|
from django.core.exceptions import ValidationError
|
|
4
|
-
|
|
5
|
-
from edc_utils import get_utcnow
|
|
4
|
+
from django.utils import timezone
|
|
6
5
|
|
|
7
6
|
|
|
8
7
|
def datetime_not_future(utc_datetime: datetime) -> None:
|
|
9
8
|
time_error = timedelta(minutes=10)
|
|
10
|
-
if utc_datetime >
|
|
9
|
+
if utc_datetime > timezone.now() + time_error:
|
|
11
10
|
raise ValidationError("Cannot be a future date/time")
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
def date_not_future(value: date) -> None:
|
|
15
|
-
if value >
|
|
14
|
+
if value > timezone.now().date():
|
|
16
15
|
raise ValidationError("Cannot be a future date")
|
|
17
16
|
|
|
18
17
|
|
|
19
18
|
def date_is_past(value: date) -> None:
|
|
20
|
-
if value >
|
|
19
|
+
if value > timezone.now().date():
|
|
21
20
|
raise ValidationError("Expected a past date")
|
|
22
21
|
|
|
23
22
|
|
|
24
23
|
def date_is_not_now(value: date) -> None:
|
|
25
|
-
if value ==
|
|
24
|
+
if value == timezone.now().date():
|
|
26
25
|
raise ValidationError("Cannot be today")
|
|
27
26
|
|
|
28
27
|
|
|
29
28
|
def datetime_is_future(utc_datetime: datetime) -> None:
|
|
30
29
|
time_error = timedelta(minutes=10)
|
|
31
|
-
if utc_datetime <
|
|
30
|
+
if utc_datetime < timezone.now() + time_error:
|
|
32
31
|
raise ValidationError("Expected a future date/time")
|
|
33
32
|
|
|
34
33
|
|
|
35
34
|
def date_is_future(value: date) -> None:
|
|
36
|
-
if value <
|
|
35
|
+
if value < timezone.now().date():
|
|
37
36
|
raise ValidationError("Expected a future date")
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
from dateutil.relativedelta import MO, relativedelta
|
|
4
4
|
from django.contrib.admin import SimpleListFilter
|
|
5
5
|
from django.db.models import QuerySet
|
|
6
|
+
from django.utils import timezone
|
|
6
7
|
from django.utils.translation import gettext as _
|
|
7
8
|
|
|
8
9
|
from edc_constants.constants import (
|
|
@@ -16,7 +17,6 @@ from edc_constants.constants import (
|
|
|
16
17
|
TODAY,
|
|
17
18
|
TOMORROW,
|
|
18
19
|
)
|
|
19
|
-
from edc_utils import get_utcnow
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
class FutureDateListFilter(SimpleListFilter):
|
|
@@ -42,9 +42,9 @@ class FutureDateListFilter(SimpleListFilter):
|
|
|
42
42
|
return {}
|
|
43
43
|
|
|
44
44
|
def queryset(self, request, queryset) -> QuerySet | None:
|
|
45
|
-
morning =
|
|
45
|
+
morning = timezone.now().replace(second=0, hour=0, minute=0)
|
|
46
46
|
monday = morning + relativedelta(weekday=MO(-1))
|
|
47
|
-
night =
|
|
47
|
+
night = timezone.now().replace(second=59, hour=23, minute=59)
|
|
48
48
|
qs = None
|
|
49
49
|
if self.value() == NEXT_WEEK:
|
|
50
50
|
qs = queryset.filter(
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
from dateutil.relativedelta import MO, relativedelta
|
|
4
4
|
from django.contrib.admin import SimpleListFilter
|
|
5
5
|
from django.db.models import QuerySet
|
|
6
|
+
from django.utils import timezone
|
|
6
7
|
from django.utils.translation import gettext as _
|
|
7
8
|
|
|
8
9
|
from edc_constants.constants import (
|
|
@@ -17,7 +18,6 @@ from edc_constants.constants import (
|
|
|
17
18
|
TODAY,
|
|
18
19
|
YESTERDAY,
|
|
19
20
|
)
|
|
20
|
-
from edc_utils import get_utcnow
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class PastDateListFilter(SimpleListFilter):
|
|
@@ -45,9 +45,9 @@ class PastDateListFilter(SimpleListFilter):
|
|
|
45
45
|
return {}
|
|
46
46
|
|
|
47
47
|
def queryset(self, request, queryset) -> QuerySet | None:
|
|
48
|
-
morning =
|
|
48
|
+
morning = timezone.now().replace(second=0, hour=0, minute=0)
|
|
49
49
|
monday = morning + relativedelta(weekday=MO(-1))
|
|
50
|
-
night =
|
|
50
|
+
night = timezone.now().replace(second=59, hour=23, minute=59)
|
|
51
51
|
qs = None
|
|
52
52
|
if self.value() == THIS_WEEK:
|
|
53
53
|
qs = queryset.filter(
|
|
@@ -21,16 +21,15 @@ class ModelAdminProtectPiiMixin:
|
|
|
21
21
|
the changelist, add the method name to `extra_pii_attrs`.
|
|
22
22
|
"""
|
|
23
23
|
|
|
24
|
-
extra_pii_attrs:
|
|
24
|
+
extra_pii_attrs: tuple[str] | None = ()
|
|
25
25
|
|
|
26
26
|
def get_extra_pii_attrs(self) -> list[str | tuple[str, str]]:
|
|
27
27
|
return self.extra_pii_attrs or []
|
|
28
28
|
|
|
29
|
-
def get_encrypted_fields(self) ->
|
|
29
|
+
def get_encrypted_fields(self) -> tuple[str, ...]:
|
|
30
30
|
encrypted_fields = [f.name for f in get_encrypted_fields(self.model)]
|
|
31
|
-
encrypted_fields.extend(self.get_extra_pii_attrs())
|
|
32
|
-
|
|
33
|
-
return encrypted_fields
|
|
31
|
+
encrypted_fields.extend(*self.get_extra_pii_attrs())
|
|
32
|
+
return tuple(set(encrypted_fields))
|
|
34
33
|
|
|
35
34
|
def get_list_display(self, request) -> tuple[str]:
|
|
36
35
|
list_display = super().get_list_display(request)
|
|
@@ -12,7 +12,7 @@ class OtherCharField(CharField):
|
|
|
12
12
|
def __init__(self, metadata=None, *args, **kwargs):
|
|
13
13
|
self.metadata = metadata
|
|
14
14
|
kwargs.update(blank=True)
|
|
15
|
-
kwargs.update(
|
|
15
|
+
kwargs.update(default="")
|
|
16
16
|
kwargs.setdefault("max_length", self.DEFAULT_MAX_LENGTH)
|
|
17
17
|
kwargs.setdefault("verbose_name", _("If other, please specify ..."))
|
|
18
18
|
self.max_length = kwargs["max_length"]
|
|
@@ -25,7 +25,7 @@ class OtherCharField(CharField):
|
|
|
25
25
|
def deconstruct(self):
|
|
26
26
|
name, path, args, kwargs = super().deconstruct()
|
|
27
27
|
kwargs.update(blank=True)
|
|
28
|
-
kwargs.update(
|
|
28
|
+
kwargs.update(default="")
|
|
29
29
|
kwargs.update(max_length=self.max_length)
|
|
30
30
|
kwargs.update(verbose_name=self.verbose_name)
|
|
31
31
|
if self.metadata is not None:
|