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
|
@@ -8,6 +8,7 @@ from django.core.validators import (
|
|
|
8
8
|
RegexValidator,
|
|
9
9
|
)
|
|
10
10
|
from django.db import models
|
|
11
|
+
from django.utils import timezone
|
|
11
12
|
from django_crypto_fields.fields import EncryptedCharField
|
|
12
13
|
|
|
13
14
|
from edc_constants.choices import GENDER, YES_NO, YES_NO_NA
|
|
@@ -15,7 +16,6 @@ from edc_constants.constants import NO, NOT_APPLICABLE
|
|
|
15
16
|
from edc_model.validators import datetime_not_future
|
|
16
17
|
from edc_protocol.validators import datetime_not_before_study_start
|
|
17
18
|
from edc_sites.model_mixins import SiteModelMixin
|
|
18
|
-
from edc_utils.date import get_utcnow
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
class ScreeningFieldsModeMixin(SiteModelMixin, models.Model):
|
|
@@ -34,7 +34,7 @@ class ScreeningFieldsModeMixin(SiteModelMixin, models.Model):
|
|
|
34
34
|
report_datetime = models.DateTimeField(
|
|
35
35
|
verbose_name="Report Date and Time",
|
|
36
36
|
validators=[datetime_not_before_study_start, datetime_not_future],
|
|
37
|
-
default=
|
|
37
|
+
default=timezone.now,
|
|
38
38
|
help_text="Date and time of report.",
|
|
39
39
|
)
|
|
40
40
|
|
|
@@ -54,7 +54,7 @@ class ScreeningFieldsModeMixin(SiteModelMixin, models.Model):
|
|
|
54
54
|
validators=[MinValueValidator(0), MaxValueValidator(110)]
|
|
55
55
|
)
|
|
56
56
|
|
|
57
|
-
ethnicity = models.CharField(max_length=25,
|
|
57
|
+
ethnicity = models.CharField(max_length=25, default="", blank=True)
|
|
58
58
|
|
|
59
59
|
consent_ability = models.CharField(
|
|
60
60
|
verbose_name="Participant or legal guardian/representative able and "
|
|
@@ -65,8 +65,7 @@ class ScreeningFieldsModeMixin(SiteModelMixin, models.Model):
|
|
|
65
65
|
|
|
66
66
|
unsuitable_for_study = models.CharField(
|
|
67
67
|
verbose_name=(
|
|
68
|
-
"Is there any other reason the patient is "
|
|
69
|
-
"deemed to not be suitable for the study?"
|
|
68
|
+
"Is there any other reason the patient is deemed to not be suitable for the study?"
|
|
70
69
|
),
|
|
71
70
|
max_length=5,
|
|
72
71
|
choices=YES_NO,
|
|
@@ -77,14 +76,13 @@ class ScreeningFieldsModeMixin(SiteModelMixin, models.Model):
|
|
|
77
76
|
reasons_unsuitable = models.TextField(
|
|
78
77
|
verbose_name="Reason not suitable for the study",
|
|
79
78
|
max_length=150,
|
|
80
|
-
|
|
79
|
+
default="",
|
|
81
80
|
blank=True,
|
|
82
81
|
)
|
|
83
82
|
|
|
84
83
|
unsuitable_agreed = models.CharField(
|
|
85
84
|
verbose_name=(
|
|
86
|
-
"Does the study coordinator agree that the patient "
|
|
87
|
-
"is not suitable for the study?"
|
|
85
|
+
"Does the study coordinator agree that the patient is not suitable for the study?"
|
|
88
86
|
),
|
|
89
87
|
max_length=5,
|
|
90
88
|
choices=YES_NO_NA,
|
|
@@ -16,7 +16,7 @@ class ScreeningMethodsModeMixin(models.Model):
|
|
|
16
16
|
|
|
17
17
|
@staticmethod
|
|
18
18
|
def get_search_slug_fields():
|
|
19
|
-
return
|
|
19
|
+
return "screening_identifier", "subject_identifier", "reference"
|
|
20
20
|
|
|
21
21
|
@property
|
|
22
22
|
def estimated_dob(self: SubjectScreeningModelStub) -> date:
|
|
@@ -174,7 +174,7 @@ class ScreeningEligibility:
|
|
|
174
174
|
setattr(
|
|
175
175
|
self.model_obj,
|
|
176
176
|
self.reasons_ineligible_fld_name,
|
|
177
|
-
"|".join(self.reasons_ineligible.values()) or
|
|
177
|
+
"|".join(self.reasons_ineligible.values()) or "",
|
|
178
178
|
)
|
|
179
179
|
self.set_eligible_model_field()
|
|
180
180
|
self.set_fld_attrs_on_model()
|
|
@@ -229,9 +229,7 @@ class ScreeningEligibility:
|
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
def formatted_reasons_ineligible(self) -> str:
|
|
232
|
-
str_values = "<BR>".join(
|
|
233
|
-
[x for x in self.reasons_ineligible.values() if x is not None]
|
|
234
|
-
)
|
|
232
|
+
str_values = "<BR>".join([x for x in self.reasons_ineligible.values() if x])
|
|
235
233
|
return format_html(
|
|
236
234
|
"{}",
|
|
237
235
|
mark_safe(str_values), # nosec B703 B308
|
edc_screening/utils.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import contextlib
|
|
3
4
|
import re
|
|
4
5
|
from typing import TYPE_CHECKING, Any
|
|
5
6
|
|
|
@@ -33,14 +34,15 @@ def get_subject_screening_model_cls() -> Any:
|
|
|
33
34
|
return django_apps.get_model(get_subject_screening_model())
|
|
34
35
|
|
|
35
36
|
|
|
36
|
-
def format_reasons_ineligible(*str_values: str, delimiter=None) -> str:
|
|
37
|
+
def format_reasons_ineligible(*str_values: str | None, delimiter: str | None = None) -> str:
|
|
37
38
|
reasons = None
|
|
38
39
|
delimiter = delimiter or "|"
|
|
39
|
-
str_values =
|
|
40
|
+
str_values = str_values or []
|
|
41
|
+
str_values = tuple(x for x in str_values if x)
|
|
40
42
|
if str_values:
|
|
41
43
|
reasons = format_html(
|
|
42
44
|
"{}",
|
|
43
|
-
mark_safe(delimiter.join(str_values)), #
|
|
45
|
+
mark_safe(delimiter.join(str_values)), # noqa: S308
|
|
44
46
|
)
|
|
45
47
|
return reasons
|
|
46
48
|
|
|
@@ -73,10 +75,10 @@ def get_subject_screening_or_raise(
|
|
|
73
75
|
)
|
|
74
76
|
except ObjectDoesNotExist as e:
|
|
75
77
|
if is_modelform:
|
|
76
|
-
raise forms.ValidationError("Not allowed. Screening form not found.")
|
|
78
|
+
raise forms.ValidationError("Not allowed. Screening form not found.") from e
|
|
77
79
|
raise ObjectDoesNotExist(
|
|
78
80
|
f"{e} screening_identifier={screening_identifier}. Perhaps catch this in the form."
|
|
79
|
-
)
|
|
81
|
+
) from e
|
|
80
82
|
return subject_screening
|
|
81
83
|
|
|
82
84
|
|
|
@@ -101,10 +103,8 @@ def is_eligible_or_raise(
|
|
|
101
103
|
)
|
|
102
104
|
|
|
103
105
|
url_name = url_name or "screening_listboard_url"
|
|
104
|
-
|
|
106
|
+
with contextlib.suppress(InvalidDashboardUrlName):
|
|
105
107
|
url_name = url_names.get(url_name)
|
|
106
|
-
except InvalidDashboardUrlName:
|
|
107
|
-
pass
|
|
108
108
|
|
|
109
109
|
if not subject_screening.eligible:
|
|
110
110
|
try:
|
|
@@ -128,7 +128,7 @@ def is_eligible_or_raise(
|
|
|
128
128
|
else:
|
|
129
129
|
msg = format_html(
|
|
130
130
|
'Not allowed. Subject is not eligible. See subject <A href="{}">{}</A>',
|
|
131
|
-
mark_safe(url), #
|
|
131
|
+
mark_safe(url), # noqa: S308
|
|
132
132
|
subject_screening.screening_identifier,
|
|
133
133
|
)
|
|
134
134
|
raise forms.ValidationError(msg)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from django.utils.text import slugify
|
|
4
|
+
from django_crypto_fields.utils import get_encrypted_field_names
|
|
5
|
+
|
|
6
|
+
SLUG_SEP = "|"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def generate_slug(obj, fields) -> str | None:
|
|
10
|
+
"""Returns a slug of the char values of the fields
|
|
11
|
+
listed on the models get_search_slug_fields() method.
|
|
12
|
+
|
|
13
|
+
Excludes any encrypted fields if listed.
|
|
14
|
+
"""
|
|
15
|
+
slug = None
|
|
16
|
+
if obj and fields:
|
|
17
|
+
values = []
|
|
18
|
+
for field in (f for f in fields if f not in get_encrypted_field_names(obj)):
|
|
19
|
+
v = obj
|
|
20
|
+
for f in field.split("."):
|
|
21
|
+
v = getattr(v, f)
|
|
22
|
+
if isinstance(v, str):
|
|
23
|
+
values.append(v[:50]) # truncate value
|
|
24
|
+
slugs = [slugify(v) for v in list(set(values)) if v]
|
|
25
|
+
slug = SLUG_SEP.join(slugs)[:250]
|
|
26
|
+
return slug
|
edc_search/model_mixins.py
CHANGED
|
@@ -1,43 +1,31 @@
|
|
|
1
1
|
from django.db import models
|
|
2
|
+
from tqdm import tqdm
|
|
2
3
|
|
|
3
|
-
from .
|
|
4
|
+
from .generate_slug import generate_slug
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
class SearchSlugManager(models.Manager):
|
|
7
|
-
search_slug_updater_cls = SearchSlugUpdater
|
|
8
|
-
search_slug_field_name = "slug"
|
|
9
|
-
|
|
10
8
|
def update_search_slugs(self) -> None:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
)
|
|
15
|
-
setattr(obj, self.search_slug_field_name, updater.slug)
|
|
16
|
-
obj.save_base(update_fields=[self.search_slug_field_name])
|
|
9
|
+
qs = self.all()
|
|
10
|
+
for obj in tqdm(qs, total=qs.count()):
|
|
11
|
+
obj.slug = generate_slug(obj, obj.get_search_slug_fields()) or ""
|
|
12
|
+
obj.save_base(update_fields=["slug"])
|
|
17
13
|
|
|
18
14
|
|
|
19
15
|
class SearchSlugModelMixin(models.Model):
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def get_search_slug_fields(self) -> list[str]:
|
|
24
|
-
return []
|
|
16
|
+
def get_search_slug_fields(self) -> tuple[str, ...]:
|
|
17
|
+
return ()
|
|
25
18
|
|
|
26
19
|
slug = models.CharField(
|
|
27
20
|
max_length=250,
|
|
28
21
|
default="",
|
|
29
|
-
null=True,
|
|
30
22
|
editable=False,
|
|
31
23
|
db_index=True,
|
|
32
|
-
help_text="
|
|
24
|
+
help_text="Hold slug field values for quick search. Excludes encrypted fields",
|
|
33
25
|
)
|
|
34
26
|
|
|
35
27
|
def save(self, *args, **kwargs):
|
|
36
|
-
|
|
37
|
-
fields=self.get_search_slug_fields(), model_obj=self
|
|
38
|
-
)
|
|
39
|
-
self.search_slug_warning = updater.warning
|
|
40
|
-
self.slug = updater.slug
|
|
28
|
+
self.slug = generate_slug(self, self.get_search_slug_fields()) or ""
|
|
41
29
|
super().save(*args, **kwargs)
|
|
42
30
|
|
|
43
31
|
class Meta:
|
edc_sites/auths.py
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
from edc_auth.site_auths import site_auths
|
|
2
2
|
from edc_auth.utils import remove_default_model_permissions_from_edc_permissions
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
|
|
5
|
+
def update_site_auths() -> None:
|
|
6
|
+
site_auths.add_post_update_func(
|
|
7
|
+
"edc_sites", remove_default_model_permissions_from_edc_permissions
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
update_site_auths()
|
|
@@ -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,69 @@
|
|
|
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_sites", "0009_alter_edcpermissions_revision"),
|
|
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="siteprofile",
|
|
51
|
+
name="country",
|
|
52
|
+
field=models.CharField(default="", max_length=250),
|
|
53
|
+
),
|
|
54
|
+
migrations.AlterField(
|
|
55
|
+
model_name="siteprofile",
|
|
56
|
+
name="country_code",
|
|
57
|
+
field=models.CharField(default="", max_length=15),
|
|
58
|
+
),
|
|
59
|
+
migrations.AlterField(
|
|
60
|
+
model_name="siteprofile",
|
|
61
|
+
name="languages",
|
|
62
|
+
field=models.TextField(default=""),
|
|
63
|
+
),
|
|
64
|
+
migrations.AlterField(
|
|
65
|
+
model_name="siteprofile",
|
|
66
|
+
name="title",
|
|
67
|
+
field=models.CharField(default="", max_length=250),
|
|
68
|
+
),
|
|
69
|
+
]
|
|
@@ -28,7 +28,7 @@ class SiteModelMixin(models.Model):
|
|
|
28
28
|
self.update_site_on_save(*args, **kwargs)
|
|
29
29
|
super().save(*args, **kwargs)
|
|
30
30
|
|
|
31
|
-
def update_site_on_save(self, *args, **kwargs) -> None:
|
|
31
|
+
def update_site_on_save(self, *args, **kwargs) -> None: # noqa: ARG002
|
|
32
32
|
if not self.id:
|
|
33
33
|
if not self.site_id and not self.site:
|
|
34
34
|
self.site = self.get_site_on_create()
|
|
@@ -59,7 +59,7 @@ class SiteModelMixin(models.Model):
|
|
|
59
59
|
"Exception raised when trying manager method `get_current()`. "
|
|
60
60
|
f"Sites registered with `sites` global are {site_ids}. "
|
|
61
61
|
f"settings.SITE_ID={settings.SITE_ID}. Got {e}."
|
|
62
|
-
)
|
|
62
|
+
) from e
|
|
63
63
|
return site_obj
|
|
64
64
|
|
|
65
65
|
def validate_site_against_current(self) -> None:
|
edc_sites/site.py
CHANGED
|
@@ -160,13 +160,13 @@ class Sites:
|
|
|
160
160
|
single_site = dataclasses.replace(single_site, domain=domain)
|
|
161
161
|
|
|
162
162
|
if single_site.site_id in self._registry:
|
|
163
|
-
raise AlreadyRegistered(f"Site already registered. Got `{single_site}`.")
|
|
163
|
+
raise AlreadyRegistered(f"Site already registered. Got `{single_site}`.")
|
|
164
164
|
if single_site.name in [s.name for s in self._registry.values()]:
|
|
165
|
-
raise AlreadyRegisteredName(
|
|
165
|
+
raise AlreadyRegisteredName(
|
|
166
166
|
f"Site with this name is already registered. Got `{single_site}`."
|
|
167
167
|
)
|
|
168
168
|
if single_site.domain in [s.domain for s in self._registry.values()]:
|
|
169
|
-
raise AlreadyRegisteredDomain(
|
|
169
|
+
raise AlreadyRegisteredDomain(
|
|
170
170
|
f"Site with this domain is already registered. Got `{single_site}`."
|
|
171
171
|
)
|
|
172
172
|
self._registry.update({single_site.site_id: single_site})
|
|
@@ -187,7 +187,7 @@ class Sites:
|
|
|
187
187
|
msg = "In fact, no sites have been registered!"
|
|
188
188
|
else:
|
|
189
189
|
msg = f"Expected one of {[s.site_id for s in self.all(aslist=True)]}."
|
|
190
|
-
raise SiteNotRegistered(
|
|
190
|
+
raise SiteNotRegistered(
|
|
191
191
|
f"Site not registered. {msg} See {self!r}. Got `{site_id}`."
|
|
192
192
|
)
|
|
193
193
|
return self._registry.get(site_id)
|
|
@@ -196,7 +196,7 @@ class Sites:
|
|
|
196
196
|
for single_site in self._registry.values():
|
|
197
197
|
if getattr(single_site, attrname) == value:
|
|
198
198
|
return single_site
|
|
199
|
-
raise SiteDoesNotExist(f"No site exists with `{attrname}`==`{value}`.")
|
|
199
|
+
raise SiteDoesNotExist(f"No site exists with `{attrname}`==`{value}`.")
|
|
200
200
|
|
|
201
201
|
def all(self, aslist: bool | None = None) -> dict[int, SingleSite] | list[SingleSite]:
|
|
202
202
|
if aslist:
|
edc_sites/system_checks.py
CHANGED
|
@@ -10,7 +10,7 @@ from edc_sites.site import sites as site_sites
|
|
|
10
10
|
from edc_sites.utils import get_site_model_cls
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
def sites_check(app_configs, **kwargs):
|
|
13
|
+
def sites_check(app_configs, **kwargs):
|
|
14
14
|
errors = []
|
|
15
15
|
if "migrate" not in sys.argv and "makemigrations" not in sys.argv:
|
|
16
16
|
try:
|
edc_subject_dashboard/auths.py
CHANGED
|
@@ -7,30 +7,35 @@ from edc_auth.constants import (
|
|
|
7
7
|
from edc_auth.site_auths import site_auths
|
|
8
8
|
from edc_auth.utils import remove_default_model_permissions_from_edc_permissions
|
|
9
9
|
|
|
10
|
-
site_auths.add_post_update_func(
|
|
11
|
-
"edc_subject_dashboard", remove_default_model_permissions_from_edc_permissions
|
|
12
|
-
)
|
|
13
|
-
|
|
14
10
|
SUBJECT_VIEW = "SUBJECT_VIEW"
|
|
15
11
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
12
|
+
|
|
13
|
+
def update_site_auths() -> None:
|
|
14
|
+
site_auths.add_post_update_func(
|
|
15
|
+
"edc_subject_dashboard", remove_default_model_permissions_from_edc_permissions
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
site_auths.add_custom_permissions_tuples(
|
|
19
|
+
model="edc_subject_dashboard.edcpermissions",
|
|
20
|
+
codename_tuples=(
|
|
21
|
+
(
|
|
22
|
+
"edc_subject_dashboard.view_subject_listboard",
|
|
23
|
+
"Can access subject listboard",
|
|
24
|
+
),
|
|
25
|
+
("edc_subject_dashboard.nav_subject_section", "Can access nav_subject_section"),
|
|
22
26
|
),
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
site_auths.add_group(
|
|
30
|
+
"edc_subject_dashboard.view_subject_listboard",
|
|
31
|
+
"edc_subject_dashboard.nav_subject_section",
|
|
32
|
+
name=SUBJECT_VIEW,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
site_auths.update_role(SUBJECT_VIEW, name=CLINICIAN_ROLE)
|
|
36
|
+
site_auths.update_role(SUBJECT_VIEW, name=NURSE_ROLE)
|
|
37
|
+
site_auths.update_role(SUBJECT_VIEW, name=CLINICIAN_SUPER_ROLE)
|
|
38
|
+
site_auths.update_role(SUBJECT_VIEW, name=AUDITOR_ROLE)
|
|
26
39
|
|
|
27
|
-
site_auths.add_group(
|
|
28
|
-
"edc_subject_dashboard.view_subject_listboard",
|
|
29
|
-
"edc_subject_dashboard.nav_subject_section",
|
|
30
|
-
name=SUBJECT_VIEW,
|
|
31
|
-
)
|
|
32
40
|
|
|
33
|
-
|
|
34
|
-
site_auths.update_role(SUBJECT_VIEW, name=NURSE_ROLE)
|
|
35
|
-
site_auths.update_role(SUBJECT_VIEW, name=CLINICIAN_SUPER_ROLE)
|
|
36
|
-
site_auths.update_role(SUBJECT_VIEW, name=AUDITOR_ROLE)
|
|
41
|
+
update_site_auths()
|
|
@@ -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,49 @@
|
|
|
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_subject_dashboard", "0004_alter_edcpermissions_revision"),
|
|
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
|
+
]
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from tempfile import mkdtemp
|
|
2
2
|
|
|
3
3
|
from django.contrib import messages
|
|
4
|
+
from django.utils import timezone
|
|
4
5
|
from reportlab.graphics.barcode import code39
|
|
5
6
|
from reportlab.lib import colors
|
|
6
7
|
from reportlab.lib.units import cm, mm
|
|
@@ -11,7 +12,6 @@ from edc_identifier.utils import convert_to_human_readable
|
|
|
11
12
|
from edc_lab.model_mixins import RequisitionModelMixin
|
|
12
13
|
from edc_lab.models.manifest.shipper import Shipper
|
|
13
14
|
from edc_pdf_reports import Report
|
|
14
|
-
from edc_utils import get_utcnow
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class RequisitionReport(Report):
|
|
@@ -33,7 +33,7 @@ class RequisitionReport(Report):
|
|
|
33
33
|
self.consignee = consignee
|
|
34
34
|
self.contact_name = f"{self.user.first_name} {self.user.last_name}"
|
|
35
35
|
self.image_folder = mkdtemp()
|
|
36
|
-
self.timestamp =
|
|
36
|
+
self.timestamp = timezone.now().strftime("%Y%m%d%H%M%S")
|
|
37
37
|
self.report_filename = f"requisition_{self.timestamp}.pdf"
|
|
38
38
|
|
|
39
39
|
@property
|
|
@@ -60,7 +60,9 @@ class RequisitionReport(Report):
|
|
|
60
60
|
Paragraph("REFERENCE", self.styles["line_label"]),
|
|
61
61
|
],
|
|
62
62
|
[
|
|
63
|
-
Paragraph(
|
|
63
|
+
Paragraph(
|
|
64
|
+
timezone.now().strftime("%Y-%m-%d"), self.styles["line_data_largest"]
|
|
65
|
+
),
|
|
64
66
|
Paragraph(
|
|
65
67
|
convert_to_human_readable(self.timestamp),
|
|
66
68
|
self.styles["line_data_largest"],
|
|
@@ -173,7 +175,7 @@ class RequisitionReport(Report):
|
|
|
173
175
|
Paragraph(self.contact_name, self.styles["line_data_large"]),
|
|
174
176
|
"",
|
|
175
177
|
Paragraph(
|
|
176
|
-
|
|
178
|
+
timezone.now().strftime("%Y-%m-%d %H:%M"),
|
|
177
179
|
self.styles["line_data_large"],
|
|
178
180
|
),
|
|
179
181
|
],
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import contextlib
|
|
2
|
+
|
|
1
3
|
from django.core.exceptions import ObjectDoesNotExist
|
|
4
|
+
from django.utils import timezone
|
|
2
5
|
|
|
3
6
|
from edc_appointment.models import Appointment
|
|
4
7
|
from edc_constants.constants import NO, YES
|
|
5
8
|
from edc_lab.constants import TUBE
|
|
6
9
|
from edc_lab.model_mixins import RequisitionModelMixin
|
|
7
|
-
from edc_utils import get_utcnow
|
|
8
10
|
|
|
9
11
|
|
|
10
12
|
class RequisitionVerifier:
|
|
@@ -22,12 +24,12 @@ class RequisitionVerifier:
|
|
|
22
24
|
if self.requisition and self.requisition.is_drawn != NO:
|
|
23
25
|
# verification fields
|
|
24
26
|
self.requisition.clinic_verified = YES
|
|
25
|
-
self.requisition.clinic_verified_datetime =
|
|
27
|
+
self.requisition.clinic_verified_datetime = timezone.now()
|
|
26
28
|
# other fields for label printing
|
|
27
29
|
self.requisition.is_drawn = self.requisition.is_drawn or YES
|
|
28
30
|
self.requisition.item_count = self.requisition.item_count or 1
|
|
29
31
|
self.requisition.item_type = self.requisition.item_type or TUBE
|
|
30
|
-
self.requisition.drawn_datetime = self.requisition.drawn_datetime or
|
|
32
|
+
self.requisition.drawn_datetime = self.requisition.drawn_datetime or timezone.now()
|
|
31
33
|
self.requisition.save()
|
|
32
34
|
self.verified = self.requisition.clinic_verified
|
|
33
35
|
|
|
@@ -43,12 +45,10 @@ class RequisitionVerifier:
|
|
|
43
45
|
def requisition(self):
|
|
44
46
|
"""Returns a requisition model instance."""
|
|
45
47
|
if not self._requisition:
|
|
46
|
-
|
|
48
|
+
with contextlib.suppress(ObjectDoesNotExist):
|
|
47
49
|
self._requisition = self.requisition_model_cls.objects.get(
|
|
48
50
|
requisition_identifier=self.requisition_identifier.strip()
|
|
49
51
|
)
|
|
50
|
-
except ObjectDoesNotExist:
|
|
51
|
-
pass
|
|
52
52
|
return self._requisition
|
|
53
53
|
|
|
54
54
|
@property
|
|
@@ -8,6 +8,7 @@ from django import template
|
|
|
8
8
|
from django.apps import apps as django_apps
|
|
9
9
|
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
|
|
10
10
|
from django.urls import reverse
|
|
11
|
+
from django.utils import timezone
|
|
11
12
|
|
|
12
13
|
from edc_appointment.constants import (
|
|
13
14
|
CANCELLED_APPT,
|
|
@@ -26,7 +27,6 @@ from edc_appointment.view_utils import AppointmentButton
|
|
|
26
27
|
from edc_auth.constants import AUDITOR_ROLE
|
|
27
28
|
from edc_metadata import KEYED, REQUIRED
|
|
28
29
|
from edc_metadata.metadata_helper import MetadataHelper
|
|
29
|
-
from edc_utils import get_utcnow
|
|
30
30
|
from edc_view_utils import PrnButton, render_history_and_query_buttons
|
|
31
31
|
from edc_visit_tracking.view_utils import RelatedVisitButton
|
|
32
32
|
|
|
@@ -171,7 +171,7 @@ def render_crf_totals(appointment: Appointment = None) -> dict[str, bool | int]:
|
|
|
171
171
|
skipped = True
|
|
172
172
|
elif (
|
|
173
173
|
appointment.appt_status == NEW_APPT
|
|
174
|
-
and appointment.appt_datetime.date() <
|
|
174
|
+
and appointment.appt_datetime.date() < timezone.now().date()
|
|
175
175
|
):
|
|
176
176
|
overdue = True
|
|
177
177
|
else:
|