clinicedc 2.0.4__py3-none-any.whl → 2.0.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of clinicedc might be problematic. Click here for more details.
- {clinicedc-2.0.4.dist-info → clinicedc-2.0.5.dist-info}/METADATA +41 -45
- {clinicedc-2.0.4.dist-info → clinicedc-2.0.5.dist-info}/RECORD +478 -478
- edc_action_item/action.py +76 -54
- edc_action_item/action_item_notification.py +1 -3
- edc_action_item/action_with_notification.py +4 -4
- edc_action_item/create_action_item.py +2 -2
- edc_action_item/create_or_update_action_type.py +1 -1
- edc_action_item/data_fixers.py +4 -5
- edc_action_item/delete_action_item.py +0 -1
- edc_action_item/modeladmin_mixins.py +2 -4
- edc_action_item/modelform_mixins/modelform_mixins.py +1 -1
- edc_action_item/models/action_item.py +53 -38
- edc_action_item/models/action_model_mixin.py +17 -17
- edc_action_item/models/action_type.py +33 -13
- edc_action_item/models/reference.py +3 -2
- edc_action_item/site_action_items.py +13 -14
- edc_action_item/stubs.py +9 -9
- edc_action_item/templatetags/action_item_extras.py +2 -2
- edc_action_item/view_utils/action_item_button.py +3 -3
- edc_action_item/view_utils/action_item_popover_list_item.py +4 -4
- edc_adherence/form_validator_mixin.py +1 -1
- edc_adverse_event/action_items/ae_followup_action.py +1 -1
- edc_adverse_event/action_items/ae_initial_action.py +1 -1
- edc_adverse_event/action_items/ae_susar_action.py +1 -1
- edc_adverse_event/action_items/ae_tmg_action.py +1 -1
- edc_adverse_event/action_items/death_report_action.py +1 -2
- edc_adverse_event/action_items/death_report_tmg_action.py +1 -1
- edc_adverse_event/action_items/death_report_tmg_second_action.py +1 -1
- edc_adverse_event/action_items/hospitalization_action.py +1 -1
- edc_adverse_event/form_validator_mixins/death_report_form_validator.py +3 -3
- edc_adverse_event/form_validator_mixins/requires_death_report_form_validator_mixin.py +3 -4
- edc_adverse_event/form_validators/death_report_tmg.py +1 -1
- edc_adverse_event/model_mixins/ae_followup/ae_followup_methods_model_mixin.py +3 -3
- edc_adverse_event/model_mixins/ae_followup/ae_followup_model_mixin.py +3 -3
- edc_adverse_event/model_mixins/ae_initial/ae_initial_fields_model_mixin.py +0 -1
- edc_adverse_event/model_mixins/ae_initial/ae_initial_methods_model_mixin.py +3 -3
- edc_adverse_event/model_mixins/ae_initial/ae_initial_model_mixin.py +3 -3
- edc_adverse_event/model_mixins/ae_special_interest/aesi_methods_model_mixin.py +4 -4
- edc_adverse_event/model_mixins/ae_special_interest/aesi_model_mixin.py +3 -3
- edc_adverse_event/model_mixins/ae_susar/ae_susar_methods_model_mixin.py +4 -4
- edc_adverse_event/model_mixins/ae_susar/ae_susar_model_mixin.py +3 -3
- edc_adverse_event/model_mixins/ae_tmg/ae_tmg_fields_model_mixin.py +4 -5
- edc_adverse_event/model_mixins/ae_tmg/ae_tmg_methods_model_mixin.py +4 -4
- edc_adverse_event/model_mixins/ae_tmg/ae_tmg_model_mixin.py +3 -3
- edc_adverse_event/model_mixins/death_report/death_report_extra_fields_model_mixin.py +2 -3
- edc_adverse_event/model_mixins/death_report/death_report_model_mixin.py +11 -11
- edc_adverse_event/model_mixins/death_report/death_report_tmg_model_mixin.py +9 -11
- edc_adverse_event/model_mixins/death_report/simple_death_report_model_mixin.py +7 -6
- edc_adverse_event/model_mixins/hospitaization/hospitalization_model_mixin.py +0 -1
- edc_adverse_event/modeladmin_mixins/ae_followup_admin_mixin.py +9 -11
- edc_adverse_event/modeladmin_mixins/ae_initial_admin_mixin.py +4 -6
- edc_adverse_event/modeladmin_mixins/modeladmin_mixins.py +1 -1
- edc_adverse_event/modeladmin_mixins/utils.py +4 -4
- edc_adverse_event/models/signals.py +7 -19
- edc_adverse_event/pdf_reports/death_pdf_report.py +8 -9
- edc_adverse_event/templatetags/edc_adverse_event_extras.py +10 -20
- edc_adverse_event/urls.py +7 -3
- edc_adverse_event/utils.py +2 -2
- edc_adverse_event/view_utils/tmg_button.py +4 -4
- edc_appconfig/system_checks.py +1 -1
- edc_appointment/appointment_status_updater.py +14 -15
- edc_appointment/creators/appointment_creator.py +7 -11
- edc_appointment/creators/appointments_creator.py +1 -1
- edc_appointment/creators/unscheduled_appointment_creator.py +12 -13
- edc_appointment/form_validator_mixins/next_appointment_crf_form_validator_mixin.py +1 -3
- edc_appointment/form_validator_mixins/window_period_form_validator_mixin.py +7 -6
- edc_appointment/form_validators/appointment_form_validator.py +2 -4
- edc_appointment/form_validators/utils.py +4 -4
- edc_appointment/managers.py +4 -4
- edc_appointment/model_mixins/appointment_methods_model_mixin.py +2 -2
- edc_appointment/model_mixins/appointment_model_mixin.py +5 -5
- edc_appointment/model_mixins/window_period_model_mixin.py +1 -1
- edc_appointment/models/appointment.py +1 -1
- edc_appointment/skip_appointments.py +5 -6
- edc_appointment/stubs.py +12 -12
- edc_appointment/utils.py +41 -47
- edc_appointment/view_utils/appointment_button.py +3 -5
- edc_auth/admin/role_admin.py +5 -7
- edc_auth/auth_objects/default_roles.py +1 -3
- edc_auth/auth_updater/auth_updater.py +5 -7
- edc_auth/auth_updater/group_updater.py +8 -8
- edc_auth/auth_updater/role_updater.py +1 -2
- edc_auth/get_app_codenames.py +1 -3
- edc_auth/import_users.py +19 -19
- edc_auth/models/role.py +4 -3
- edc_auth/password_setter.py +6 -7
- edc_auth/send_new_credentials_to_user.py +2 -3
- edc_auth/site_auths.py +3 -3
- edc_consent/actions.py +4 -5
- edc_consent/consent_definition.py +8 -11
- edc_consent/consent_definition_extension.py +3 -3
- edc_consent/form_validators/__init__.py +1 -1
- edc_consent/model_mixins/__init__.py +2 -2
- edc_consent/model_mixins/consent_version_model_mixin.py +1 -1
- edc_consent/modeladmin_mixins/consent_model_admin_mixin.py +1 -2
- edc_consent/modelform_mixins/consent_modelform_mixin/consent_modelform_validation_mixin.py +3 -5
- edc_consent/site_consents.py +10 -15
- edc_consent/stubs.py +2 -2
- edc_consent/utils.py +1 -1
- edc_constants/utils.py +2 -4
- edc_crf/crf_form_validator_mixins.py +2 -2
- edc_crf/model_mixins/crf_no_manager_model_mixin.py +2 -2
- edc_crf/model_mixins/crf_status_model_mixin.py +1 -1
- edc_crf/models/crf_status.py +10 -12
- edc_crf/update_crf_status_command.py +1 -3
- edc_dashboard/management/commands/update_search_slugs.py +8 -11
- edc_dashboard/templatetags/edc_dashboard_extras.py +1 -1
- edc_dashboard/url_config.py +3 -3
- edc_dashboard/utils.py +3 -4
- edc_dashboard/views/dashboard_view.py +1 -1
- edc_data_manager/models/data_dictionary.py +1 -2
- edc_data_manager/models/data_query.py +3 -3
- edc_data_manager/models/query_rule.py +2 -2
- edc_data_manager/tasks.py +0 -2
- edc_device/device.py +1 -1
- edc_device/view_mixins.py +1 -1
- edc_document_status/fieldsets.py +1 -3
- edc_document_status/model_mixins.py +2 -2
- edc_document_status/modeladmin_mixins.py +1 -4
- edc_egfr/admin/egfr_drop_notification_admin_mixin.py +5 -7
- edc_egfr/egfr.py +6 -7
- edc_egfr/get_drop_notification_model.py +1 -1
- edc_egfr/model_mixins/egfr_drop_notification_model_mixin.py +1 -1
- edc_export/archive_exporter.py +26 -27
- edc_export/exportables.py +2 -3
- edc_export/management/commands/import_receipts.py +6 -6
- edc_export/model_exporter/file_history_updater.py +1 -1
- edc_export/model_exporter/model_exporter.py +1 -1
- edc_export/model_exporter/value_getter.py +6 -6
- edc_export/model_mixins/notification_model_mixin.py +4 -4
- edc_export/models/data_request.py +3 -3
- edc_export/models/data_request_history.py +2 -2
- edc_export/models/export_receipt.py +1 -1
- edc_export/models/file_history.py +5 -5
- edc_export/models/plan.py +4 -4
- edc_export/models/upload_export_receipt_file.py +2 -2
- edc_export/utils.py +1 -1
- edc_facility/facility.py +6 -6
- edc_facility/holidays.py +2 -5
- edc_facility/import_holidays.py +6 -6
- edc_facility/model_mixins.py +1 -1
- edc_facility/models/holiday.py +1 -1
- edc_facility/utils.py +3 -3
- edc_fieldsets/fieldsets.py +1 -1
- edc_form_describer/forms_reference.py +5 -8
- edc_form_describer/make_forms_reference.py +1 -1
- edc_form_describer/management/commands/make_forms_reference.py +1 -1
- edc_form_label/custom_label_condition.py +1 -1
- edc_form_label/form_label.py +2 -2
- edc_form_runners/exceptions.py +1 -1
- edc_form_runners/models/issue.py +3 -2
- edc_form_runners/site.py +2 -2
- edc_form_runners/templatetags/form_runners_extras.py +1 -1
- edc_form_runners/utils.py +5 -5
- edc_form_validators/applicable_field_validator.py +32 -32
- edc_form_validators/base_form_validator.py +1 -1
- edc_form_validators/extra_mixins/study_day_form_validator.py +1 -1
- edc_form_validators/many_to_many_field_validator.py +38 -43
- edc_form_validators/other_specify_field_validator.py +9 -17
- edc_form_validators/required_field_validator.py +34 -39
- edc_form_validators/test_case_mixin.py +5 -5
- edc_identifier/admin.py +1 -3
- edc_identifier/identifier.py +2 -3
- edc_identifier/model_mixins.py +5 -8
- edc_identifier/research_identifier.py +10 -12
- edc_identifier/short_identifier.py +1 -1
- edc_identifier/simple_identifier.py +22 -22
- edc_identifier/utils.py +1 -1
- edc_lab/admin/fieldsets.py +7 -9
- edc_lab/admin/modeladmin_mixins.py +5 -6
- edc_lab/form_validators/requisition_form_validator_mixin.py +2 -3
- edc_lab/forms/box_form.py +5 -11
- edc_lab/identifiers/aliquot_identifier.py +5 -8
- edc_lab/identifiers/prefix.py +2 -5
- edc_lab/lab/aliquot_creator.py +1 -2
- edc_lab/lab/aliquot_type.py +2 -4
- edc_lab/lab/manifest.py +5 -7
- edc_lab/lab/requisition_panel.py +2 -4
- edc_lab/lab/requisition_panel_group.py +5 -7
- edc_lab/model_mixins/requisition/requisition_model_mixin.py +5 -4
- edc_lab/model_mixins/shipping/manifest_model_mixin.py +6 -6
- edc_lab/model_mixins/shipping/verify_model_mixin.py +4 -3
- edc_lab/models/aliquot.py +1 -1
- edc_lab/models/box.py +2 -2
- edc_lab/models/box_item.py +1 -1
- edc_lab/models/box_type.py +1 -1
- edc_lab/models/manifest/manifest_item.py +1 -1
- edc_lab/pdf_reports/manifest_pdf_report.py +3 -7
- edc_lab/site_labs.py +3 -3
- edc_lab_dashboard/dashboard_templates.py +1 -1
- edc_lab_dashboard/view_mixins/box_view_mixin.py +4 -9
- edc_lab_dashboard/views/action_views/action_view.py +1 -2
- edc_lab_dashboard/views/action_views/manage_manifest_view.py +1 -1
- edc_lab_dashboard/views/action_views/manifest_view.py +9 -11
- edc_lab_dashboard/views/action_views/pack_view.py +11 -14
- edc_lab_results/calculate_missing.py +2 -2
- edc_lab_results/fieldsets.py +6 -6
- edc_lab_results/model_mixin_factories/__init__.py +2 -2
- edc_lab_results/model_mixin_factories/reportable_result_model_mixin_factory.py +7 -9
- edc_lab_results/model_mixin_factories/result_model_mixin_factory.py +7 -9
- edc_lab_results/model_mixins/fbg_model_mixin.py +1 -1
- edc_lab_results/model_mixins/glucose_model_mixin.py +1 -1
- edc_label/admin.py +1 -3
- edc_label/label.py +2 -4
- edc_label/label_template.py +1 -1
- edc_label/subject_label.py +1 -3
- edc_list_data/admin.py +3 -5
- edc_list_data/load_list_data.py +1 -1
- edc_list_data/load_model_data.py +1 -3
- edc_list_data/model_mixins.py +3 -5
- edc_list_data/preload_data.py +2 -4
- edc_list_data/site_list_data.py +6 -7
- edc_listboard/filters/listboard_filter.py +2 -2
- edc_listboard/views/listboard_view.py +1 -3
- edc_locator/models.py +2 -2
- edc_locator/view_mixins/subject_locator_view_mixins.py +2 -2
- edc_ltfu/action_items.py +1 -1
- edc_ltfu/model_mixins.py +0 -2
- edc_ltfu/models.py +4 -4
- edc_metadata/admin/modeladmin_mixins.py +1 -1
- edc_metadata/admin/requisition_metadata.py +2 -4
- edc_metadata/metadata/crf_metadata_getter.py +1 -3
- edc_metadata/metadata/requisition_metadata_getter.py +1 -3
- edc_metadata/metadata_handler.py +2 -2
- edc_metadata/metadata_helper/metadata_helper_mixin.py +2 -3
- edc_metadata/metadata_mixins/source_model_metadata_mixin.py +2 -2
- edc_metadata/metadata_refresher.py +1 -1
- edc_metadata/metadata_rules/crf/crf_rule_group.py +3 -5
- edc_metadata/metadata_rules/logic.py +1 -1
- edc_metadata/metadata_rules/requisition/requisition_rule.py +4 -4
- edc_metadata/metadata_rules/requisition/requisition_rule_group.py +2 -2
- edc_metadata/metadata_rules/rule_evaluator.py +5 -6
- edc_metadata/metadata_rules/rule_group_metaclass.py +2 -3
- edc_metadata/metadata_rules/site.py +6 -7
- edc_metadata/metadata_updater.py +2 -2
- edc_metadata/metadata_wrappers/metadata_wrapper.py +4 -4
- edc_metadata/model_mixins/creates/creates_metadata_model_mixin.py +6 -7
- edc_metadata/model_mixins/updates/updates_crf_metadata_model_mixin.py +2 -2
- edc_metadata/model_mixins/updates/updates_metadata_model_mixin.py +2 -2
- edc_metadata/model_mixins/updates/updates_requisition_metadata_model_mixin.py +2 -2
- edc_metadata/models/crf_metadata.py +27 -29
- edc_metadata/models/crf_metadata_model_mixin.py +1 -1
- edc_metadata/models/requisition_metadata.py +29 -31
- edc_metadata/stubs.py +17 -17
- edc_metadata/utils.py +4 -4
- edc_model/__init__.py +2 -2
- edc_model/models/historical_records.py +2 -2
- edc_model/models/signals.py +1 -1
- edc_model/models/url_model_mixin.py +1 -1
- edc_model/utils.py +0 -2
- edc_model_admin/dashboard/model_admin_dashboard_mixin.py +1 -3
- edc_model_admin/history/model_admin_simple_history.py +7 -9
- edc_model_admin/mixins/base_model_admin_redirect_mixin.py +4 -6
- edc_model_admin/mixins/model_admin_limit_to_selected_foreignkey.py +2 -2
- edc_model_admin/mixins/model_admin_model_redirect_mixin.py +2 -10
- edc_model_admin/mixins/model_admin_next_url_redirect_mixin.py +8 -9
- edc_model_admin/utils.py +6 -9
- edc_model_form/mixins/__init__.py +1 -1
- edc_model_form/mixins/base_model_form_mixin.py +1 -1
- edc_model_to_dataframe/model_to_dataframe.py +2 -4
- edc_navbar/site_navbars.py +2 -2
- edc_navbar/system_checks.py +1 -1
- edc_notification/mailing_list_manager.py +5 -8
- edc_notification/management/commands/list_recipients_by_notification.py +1 -1
- edc_notification/models/__init__.py +4 -2
- edc_notification/notification/graded_event_notification.py +2 -4
- edc_notification/notification/model_notification.py +1 -3
- edc_notification/notification/notification.py +14 -17
- edc_notification/site_notifications.py +7 -7
- edc_notification/stubs.py +6 -6
- edc_notification/update_mailing_lists_in_m2m.py +2 -2
- edc_offstudy/action_items.py +2 -2
- edc_offstudy/model_mixins/offstudy_model_mixin.py +1 -1
- edc_offstudy/models.py +1 -1
- edc_pdf_reports/crf_pdf_report.py +2 -2
- edc_pdf_reports/model_mixins.py +2 -2
- edc_pdf_reports/report.py +4 -5
- edc_pdf_reports/utils.py +1 -1
- edc_pdutils/dataframes/get_subject_consent.py +1 -3
- edc_pdutils/df_exporters/csv_exporter.py +5 -7
- edc_pdutils/df_exporters/tables_exporter.py +2 -2
- edc_pdutils/df_handlers/crf_df_handler.py +1 -2
- edc_pdutils/dialects/crf_dialect.py +3 -3
- edc_pdutils/management/commands/export_models.py +6 -7
- edc_pdutils/site_values_mappings.py +2 -2
- edc_pdutils/utils/datetime_to_date.py +1 -2
- edc_pdutils/utils/refresh_model_from_dataframe.py +1 -3
- edc_pdutils/utils/table_names.py +2 -4
- edc_pdutils/utils/undash.py +1 -1
- edc_pharmacy/admin/medication/assignment_admin.py +2 -4
- edc_pharmacy/admin/medication/dosage_guideline_admin.py +2 -4
- edc_pharmacy/admin/medication/formulation_admin.py +3 -5
- edc_pharmacy/admin/medication/medication_admin.py +3 -5
- edc_pharmacy/admin/prescription/rx_refill_admin.py +7 -9
- edc_pharmacy/admin/stock/lot_admin.py +5 -7
- edc_pharmacy/admin/stock/order_admin.py +2 -2
- edc_pharmacy/admin/stock/order_item_admin.py +6 -6
- edc_pharmacy/admin/stock/receive_admin.py +1 -1
- edc_pharmacy/admin/stock/receive_item_admin.py +2 -2
- edc_pharmacy/admin/stock/stock_request_admin.py +4 -6
- edc_pharmacy/dosage_calculator.py +4 -4
- edc_pharmacy/form_validators/crf/study_medication_form_validator.py +8 -8
- edc_pharmacy/forms/stock/stock_request_form.py +2 -4
- edc_pharmacy/model_mixins/study_medication_crf_model_mixin.py +2 -2
- edc_pharmacy/models/medication/formulation.py +3 -4
- edc_pharmacy/models/medication/medication.py +1 -2
- edc_pharmacy/models/prescription/rx.py +2 -2
- edc_pharmacy/models/prescription/rx_refill.py +7 -9
- edc_pharmacy/models/reports/stock_availability.py +3 -4
- edc_pharmacy/models/stock/confirmation_at_site.py +1 -3
- edc_pharmacy/models/stock/order.py +1 -2
- edc_pharmacy/models/stock/receive.py +3 -4
- edc_pharmacy/models/stock/receive_item.py +2 -3
- edc_pharmacy/models/stock/stock.py +1 -2
- edc_pharmacy/models/stock/stock_adjustment.py +1 -2
- edc_pharmacy/models/stock/stock_request.py +4 -5
- edc_pharmacy/models/storage/box.py +1 -1
- edc_pharmacy/models/storage/items/container_model_mixin.py +1 -1
- edc_pharmacy/models/storage/room.py +1 -1
- edc_pharmacy/models/storage/shelf.py +1 -1
- edc_pharmacy/models/storage/utils.py +15 -16
- edc_pharmacy/prescribe/create_prescription.py +5 -5
- edc_pharmacy/refill/refill_creator.py +1 -1
- edc_pharmacy/sample_usb_printing/usb_printing.py +1 -1
- edc_pharmacy/utils/__init__.py +1 -1
- edc_pharmacy/utils/confirm_stock.py +3 -3
- edc_pharmacy/utils/confirm_stock_at_site.py +9 -8
- edc_pharmacy/utils/dispense.py +5 -8
- edc_pharmacy/utils/format_qty.py +3 -3
- edc_pharmacy/utils/get_codenames.py +1 -1
- edc_pharmacy/utils/miscellaneous.py +1 -1
- edc_pharmacy/utils/process_repack_request.py +18 -19
- edc_pharmacy/utils/process_repack_request_queryset.py +0 -2
- edc_pharmacy/utils/stock_request/bulk_create_stock_request_items.py +2 -3
- edc_pharmacy/views/add_to_storage_bin_view.py +1 -1
- edc_pharmacy/views/allocate_to_subject_view.py +2 -6
- edc_pharmacy/views/confirm_stock_from_instance_view.py +4 -4
- edc_pharmacy/views/confirm_stock_from_queryset_view.py +1 -5
- edc_pharmacy/views/confirmation_at_site_view.py +2 -3
- edc_pharmacy/views/dispense_view.py +1 -1
- edc_pharmacy/views/move_to_storage_bin_view.py +2 -3
- edc_pharmacy/views/print_labels_view.py +30 -31
- edc_pharmacy/views/transfer_stock_view.py +1 -1
- edc_prn/prn.py +1 -1
- edc_prn/site_prn_forms.py +1 -2
- edc_protocol_incident/action_items.py +2 -2
- edc_protocol_incident/model_mixins/protocol_deviation_violation_model_mixin.py +3 -3
- edc_protocol_incident/model_mixins/protocol_incident_model_mixin.py +3 -5
- edc_protocol_incident/modeladmin_mixins.py +3 -5
- edc_protocol_incident/models/protocol_deviation_violation.py +5 -5
- edc_protocol_incident/models/protocol_incident.py +5 -5
- edc_pylabels/site_label_configs.py +5 -5
- edc_qareports/model_mixins/qa_report_model_mixin.py +4 -2
- edc_qareports/models/qa_reports_log.py +1 -2
- edc_qareports/utils.py +1 -2
- edc_randomization/admin.py +3 -5
- edc_randomization/auth_objects.py +2 -3
- edc_randomization/blinding.py +1 -1
- edc_randomization/constants.py +2 -4
- edc_randomization/model_mixins.py +3 -3
- edc_randomization/randomization_list_importer.py +13 -14
- edc_randomization/randomization_list_verifier.py +11 -13
- edc_randomization/randomizer.py +2 -2
- edc_randomization/system_checks.py +1 -2
- edc_randomization/utils.py +5 -5
- edc_refusal/admin.py +1 -1
- edc_refusal/model_mixins.py +1 -1
- edc_refusal/utils.py +1 -1
- edc_registration/model_mixins/updates_or_creates_registered_subject_model_mixin.py +2 -2
- edc_registration/modeladmin_mixins.py +4 -7
- edc_registration/models/registered_subject.py +7 -9
- edc_registration/utils.py +3 -4
- edc_reportable/data/grading_data/daids_july_2017.py +3 -3
- edc_reportable/evaluator.py +5 -5
- edc_reportable/formula.py +1 -1
- edc_reportable/reference_range_evaluator.py +3 -3
- edc_reportable/utils/convert_units.py +10 -12
- edc_reportable/utils/grading_data_model_cls.py +2 -2
- edc_reportable/utils/grading_exception_model_cls.py +2 -2
- edc_reportable/utils/molecular_weight_model_cls.py +2 -2
- edc_reportable/utils/normal_data_model_cls.py +2 -2
- edc_reportable/utils/reference_range_colllection_model_cls.py +2 -2
- edc_screening/age_evaluator.py +2 -4
- edc_screening/eligibility.py +1 -1
- edc_screening/form_validator_mixins.py +2 -2
- edc_screening/model_mixins/screening_methods_model_mixin.py +1 -1
- edc_screening/screening_eligibility.py +1 -1
- edc_screening/utils.py +4 -6
- edc_search/model_mixins.py +1 -1
- edc_search/search_slug.py +1 -3
- edc_search/updater.py +1 -1
- edc_sites/admin/site_model_admin_mixin.py +2 -2
- edc_sites/model_mixins/site_model_mixin.py +1 -2
- edc_sites/modelform_mixins.py +2 -2
- edc_sites/models/__init__.py +1 -1
- edc_sites/models/site_profile.py +4 -4
- edc_sites/site.py +24 -32
- edc_sites/system_checks.py +1 -1
- edc_sites/utils/get_message_text.py +1 -1
- edc_sites/utils/valid_site_for_subject_or_raise.py +5 -6
- edc_subject_dashboard/requisition_report.py +4 -5
- edc_subject_dashboard/requisition_verifier.py +4 -2
- edc_subject_dashboard/templatetags/edc_subject_dashboard_extras.py +16 -17
- edc_subject_dashboard/view_utils/__init__.py +1 -1
- edc_subject_dashboard/view_utils/crf_button.py +1 -3
- edc_subject_dashboard/view_utils/subject_consent_dashboard_button.py +2 -2
- edc_subject_dashboard/view_utils/subject_consent_listboard_button.py +2 -2
- edc_subject_dashboard/view_utils/timepoint_status_button.py +1 -4
- edc_subject_dashboard/views/requisition_print_actions_view.py +2 -2
- edc_subject_dashboard/views/subject_dashboard_view.py +1 -1
- edc_timepoint/model_mixins.py +2 -2
- edc_transfer/action_items.py +1 -1
- edc_transfer/model_mixins.py +4 -3
- edc_transfer/modeladmin_mixins.py +3 -6
- edc_unblinding/action_items.py +2 -2
- edc_unblinding/models/unblinding_request.py +3 -3
- edc_unblinding/models/unblinding_review.py +3 -3
- edc_utils/__init__.py +6 -5
- edc_utils/age.py +1 -1
- edc_utils/celery.py +3 -8
- edc_utils/get_static_file.py +1 -1
- edc_utils/text.py +5 -6
- edc_view_utils/__init__.py +3 -3
- edc_view_utils/dashboard_model_button.py +4 -4
- edc_view_utils/model_button.py +7 -8
- edc_view_utils/perms.py +3 -3
- edc_visit_schedule/action_items.py +2 -2
- edc_visit_schedule/admin/list_filters.py +11 -9
- edc_visit_schedule/admin/subject_schedule_history_admin.py +13 -15
- edc_visit_schedule/admin/visit_schedule_admin.py +7 -7
- edc_visit_schedule/fieldsets.py +4 -6
- edc_visit_schedule/management/commands/find_invalid_onschedules.py +1 -1
- edc_visit_schedule/model_mixins/off_schedule_model_mixin.py +3 -1
- edc_visit_schedule/model_mixins/on_schedule_model_mixin.py +1 -1
- edc_visit_schedule/modelform_mixins/__init__.py +1 -1
- edc_visit_schedule/modelform_mixins/off_schedule_modelform_mixin.py +1 -2
- edc_visit_schedule/models/subject_schedule_history.py +2 -1
- edc_visit_schedule/models/visit_schedule.py +2 -2
- edc_visit_schedule/schedule/schedule.py +11 -12
- edc_visit_schedule/schedule/visit_collection.py +4 -3
- edc_visit_schedule/schedule/window.py +19 -12
- edc_visit_schedule/site_visit_schedules.py +9 -9
- edc_visit_schedule/subject_schedule.py +6 -7
- edc_visit_schedule/system_checks.py +1 -1
- edc_visit_schedule/view_mixins.py +1 -1
- edc_visit_schedule/visit/crf.py +3 -7
- edc_visit_schedule/visit/requisition.py +2 -2
- edc_visit_schedule/visit/visit.py +6 -7
- edc_visit_schedule/visit/window_period.py +8 -8
- edc_visit_schedule/visit_schedule/schedules_collection.py +2 -5
- edc_visit_tracking/action_items.py +11 -13
- edc_visit_tracking/form_validators/visit_form_validator.py +5 -5
- edc_visit_tracking/model_mixins/base/visit_methods_model_mixin.py +3 -4
- edc_visit_tracking/model_mixins/crfs/visit_tracking_crf_model_mixin.py +2 -2
- edc_visit_tracking/model_mixins/subject_visit_missed_model_mixin.py +2 -3
- edc_visit_tracking/model_mixins/utils.py +1 -1
- edc_visit_tracking/model_mixins/visit_model_mixin/previous_visit_model_mixin.py +2 -2
- edc_visit_tracking/model_mixins/visit_model_mixin/visit_model_mixin.py +3 -3
- edc_visit_tracking/modeladmin_mixins/crf_model_admin_mixin.py +6 -4
- edc_visit_tracking/modeladmin_mixins/visit_model_admin_mixin.py +6 -7
- edc_visit_tracking/modelform_mixins/crf/visit_tracking_crf_modelform_mixin.py +4 -5
- edc_visit_tracking/modelform_mixins/visit_tracking_modelform_mixin.py +3 -4
- edc_visit_tracking/models/subject_visit.py +1 -1
- edc_visit_tracking/models/subject_visit_missed.py +1 -1
- edc_visit_tracking/stubs.py +7 -7
- edc_visit_tracking/typing_stubs.py +11 -11
- edc_visit_tracking/utils.py +5 -5
- edc_visit_tracking/view_utils/related_visit_button.py +5 -5
- edc_vitals/calculators/bmi.py +1 -1
- edc_vitals/form_validators/blood_pressure_form_validator_mixin.py +8 -12
- edc_vitals/form_validators/bmi_form_validator_mixin.py +1 -1
- edc_vitals/form_validators/weight_height_with_bmi_form_validator_mixin.py +5 -2
- edc_vitals/model_mixins/blood_pressure_model_mixin.py +3 -4
- edc_vitals/model_mixins/weight_height_bmi_model_mixin.py +4 -4
- edc_vitals/utils.py +1 -1
- edc_vitals/validators.py +1 -1
- {clinicedc-2.0.4.dist-info → clinicedc-2.0.5.dist-info}/WHEEL +0 -0
- {clinicedc-2.0.4.dist-info → clinicedc-2.0.5.dist-info}/licenses/LICENSE +0 -0
edc_pdf_reports/model_mixins.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from django.core.handlers.wsgi import WSGIRequest
|
|
6
6
|
|
|
@@ -14,7 +14,7 @@ if TYPE_CHECKING:
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class PdfReportModelMixin:
|
|
17
|
-
pdf_report_cls:
|
|
17
|
+
pdf_report_cls: type[CrfPdfReport]
|
|
18
18
|
|
|
19
19
|
def get_pdf_report(self: ModelMixin, request: WSGIRequest):
|
|
20
20
|
return self.pdf_report_cls(model_obj=self, request=request, user=request.user)
|
edc_pdf_reports/report.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from abc import ABC
|
|
4
|
-
from typing import Type
|
|
5
4
|
from uuid import uuid4
|
|
6
5
|
|
|
7
6
|
from django.conf import settings
|
|
@@ -48,7 +47,7 @@ class Report(ABC):
|
|
|
48
47
|
header_line: str | None = None,
|
|
49
48
|
filename: str | None = None,
|
|
50
49
|
request: WSGIRequest | None = None,
|
|
51
|
-
numbered_canvas:
|
|
50
|
+
numbered_canvas: type[NumberedCanvas] | None = None,
|
|
52
51
|
footer_row_height: int | None = None,
|
|
53
52
|
):
|
|
54
53
|
self._styles = None
|
|
@@ -77,12 +76,12 @@ class Report(ABC):
|
|
|
77
76
|
return self._numbered_canvas
|
|
78
77
|
|
|
79
78
|
@numbered_canvas.setter
|
|
80
|
-
def numbered_canvas(self, value:
|
|
79
|
+
def numbered_canvas(self, value: type[NumberedCanvas]):
|
|
81
80
|
self._numbered_canvas = value
|
|
82
81
|
if self.watermark_word:
|
|
83
|
-
|
|
82
|
+
self._numbered_canvas.watermark_word = self.watermark_word
|
|
84
83
|
if self.watermark_font:
|
|
85
|
-
|
|
84
|
+
self._numbered_canvas.watermark_font = self.watermark_font
|
|
86
85
|
|
|
87
86
|
@property
|
|
88
87
|
def report_filename(self) -> str:
|
edc_pdf_reports/utils.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Type
|
|
2
|
-
|
|
3
1
|
import numpy as np
|
|
4
2
|
import pandas as pd
|
|
5
3
|
from django.apps import apps as django_apps
|
|
@@ -13,7 +11,7 @@ from ..utils import convert_dates_from_model
|
|
|
13
11
|
|
|
14
12
|
def get_subject_consent(
|
|
15
13
|
model: str | None = None,
|
|
16
|
-
model_cls:
|
|
14
|
+
model_cls: type[Model] | None = None,
|
|
17
15
|
subject_identifiers: list[str] | None = None,
|
|
18
16
|
extra_columns: list[str] | None = None,
|
|
19
17
|
normalize: bool | None = None,
|
|
@@ -129,11 +129,10 @@ class CsvExporter:
|
|
|
129
129
|
record_count = len(dataframe)
|
|
130
130
|
if self.verbose:
|
|
131
131
|
sys.stdout.write(
|
|
132
|
-
f
|
|
132
|
+
f"({style.SUCCESS('*')}) {self.model_name} {record_count} \n"
|
|
133
133
|
)
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
sys.stdout.write(f"(?) {self.model_name} empty \n")
|
|
134
|
+
elif self.verbose:
|
|
135
|
+
sys.stdout.write(f"(?) {self.model_name} empty \n")
|
|
137
136
|
return Exported(path, self.model_name, record_count)
|
|
138
137
|
|
|
139
138
|
def to_csv(self, dataframe: pd.DataFrame = None, export_folder: str = None) -> Exported:
|
|
@@ -244,14 +243,13 @@ class CsvExporter:
|
|
|
244
243
|
if fname in list(dataframe.columns):
|
|
245
244
|
for stored, displayed in responses:
|
|
246
245
|
labels.append(f'"{stored}" "{displayed}"')
|
|
247
|
-
commands.append(f
|
|
246
|
+
commands.append(f"label define {fname}l {' '.join(labels)}")
|
|
248
247
|
commands.append(f"encode {fname}, generate({fname}_encoded) {fname}l")
|
|
249
248
|
commands.append(f"ren {fname} {fname}_edc")
|
|
250
249
|
commands.append(f"ren {fname}_encoded {fname}")
|
|
251
250
|
commands.append("")
|
|
252
251
|
with open(f"{self.get_path()}.do", "w") as f:
|
|
253
|
-
for command in commands
|
|
254
|
-
f.write(f"{command}\n")
|
|
252
|
+
f.writelines(f"{command}\n" for command in commands)
|
|
255
253
|
return commands
|
|
256
254
|
|
|
257
255
|
def data_dictionary_qs(self, dataframe: pd.DataFrame) -> QuerySet:
|
|
@@ -48,7 +48,7 @@ class TablesExporter:
|
|
|
48
48
|
):
|
|
49
49
|
self.app_label = app_label or self.app_label
|
|
50
50
|
if not self.app_label:
|
|
51
|
-
raise TablesExporterError(f"Missing app_label. Got None. See {
|
|
51
|
+
raise TablesExporterError(f"Missing app_label. Got None. See {self!r}")
|
|
52
52
|
self.export_folder = export_folder or get_export_folder()
|
|
53
53
|
self.with_columns = with_columns or []
|
|
54
54
|
self.without_columns = without_columns or []
|
|
@@ -63,7 +63,7 @@ class TablesExporter:
|
|
|
63
63
|
self.table_names = self.get_table_names()
|
|
64
64
|
if not self.table_names:
|
|
65
65
|
raise TablesExporterError(
|
|
66
|
-
f"No tables found for app_label. Got {self.app_label}. See {
|
|
66
|
+
f"No tables found for app_label. Got {self.app_label}. See {self!r}"
|
|
67
67
|
)
|
|
68
68
|
for hint in exclude_table_hints:
|
|
69
69
|
for table_name in self.get_table_names():
|
|
@@ -36,8 +36,7 @@ class CrfDfHandler(DfHandler):
|
|
|
36
36
|
"""
|
|
37
37
|
if not self.visit_column:
|
|
38
38
|
raise CrfDfHandlerError(
|
|
39
|
-
f"visit column cannot be None. "
|
|
40
|
-
f"See class attr 'visit_column' on {repr(self)}"
|
|
39
|
+
f"visit column cannot be None. See class attr 'visit_column' on {self!r}"
|
|
41
40
|
)
|
|
42
41
|
self.dataframe = pd.merge(
|
|
43
42
|
left=self.dataframe,
|
|
@@ -19,7 +19,7 @@ class CrfDialect:
|
|
|
19
19
|
f"LEFT JOIN {self.obj.visit_tbl} as V on A.id=V.appointment_id " # nosec
|
|
20
20
|
f"LEFT JOIN {self.obj.registered_subject_tbl} as R " # nosec
|
|
21
21
|
"on A.subject_identifier=R.subject_identifier " # nosec
|
|
22
|
-
)
|
|
22
|
+
)
|
|
23
23
|
return sql, None
|
|
24
24
|
|
|
25
25
|
@property
|
|
@@ -46,7 +46,7 @@ class CrfDialect:
|
|
|
46
46
|
"on A.visit_definition_id=VDEF.id " # nosec
|
|
47
47
|
f"LEFT JOIN {self.obj.registered_subject_tbl} as R " # nosec
|
|
48
48
|
"on A.registered_subject_id=R.id " # nosec
|
|
49
|
-
)
|
|
49
|
+
)
|
|
50
50
|
return sql, None
|
|
51
51
|
|
|
52
52
|
@property
|
|
@@ -69,5 +69,5 @@ class CrfDialect:
|
|
|
69
69
|
"on A.visit_definition_id=VDEF.id " # nosec
|
|
70
70
|
f"LEFT JOIN {self.obj.registered_subject_tbl} as R " # nosec
|
|
71
71
|
"on A.registered_subject_id=R.id " # nosec
|
|
72
|
-
)
|
|
72
|
+
)
|
|
73
73
|
return sql, None
|
|
@@ -223,14 +223,13 @@ class Command(BaseCommand):
|
|
|
223
223
|
countries = options["countries"] or []
|
|
224
224
|
if not countries:
|
|
225
225
|
raise CommandError("Expected country.")
|
|
226
|
+
if countries == ALL_COUNTRIES:
|
|
227
|
+
countries = sites.countries
|
|
226
228
|
else:
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
for country in countries:
|
|
232
|
-
if country not in sites.countries:
|
|
233
|
-
raise CommandError(f"Invalid country. Got {country}.")
|
|
229
|
+
countries = options["countries"].lower().split(",")
|
|
230
|
+
for country in countries:
|
|
231
|
+
if country not in sites.countries:
|
|
232
|
+
raise CommandError(f"Invalid country. Got {country}.")
|
|
234
233
|
return countries
|
|
235
234
|
|
|
236
235
|
def get_models(
|
|
@@ -59,7 +59,7 @@ class SiteValuesMappings:
|
|
|
59
59
|
try:
|
|
60
60
|
values_mapping.append((index, str(choice[1][::79])))
|
|
61
61
|
except IndexError as e:
|
|
62
|
-
raise IndexError(f"{
|
|
62
|
+
raise IndexError(f"{e!s} Got {choice[1]}")
|
|
63
63
|
return tuple(values_mapping)
|
|
64
64
|
|
|
65
65
|
def get_by_choices(self, tpl: tuple[tuple[str, Any]]) -> tuple[tuple[int, str]] | None:
|
|
@@ -87,7 +87,7 @@ class SiteValuesMappings:
|
|
|
87
87
|
except ImportError as e:
|
|
88
88
|
site_values_mappings.registry = before_import_registry
|
|
89
89
|
if module_has_submodule(mod, module_name):
|
|
90
|
-
raise SiteValuesMappingError(f"{
|
|
90
|
+
raise SiteValuesMappingError(f"{e!s}. See {app}.{module_name}")
|
|
91
91
|
except ImportError:
|
|
92
92
|
pass
|
|
93
93
|
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Type
|
|
2
|
-
|
|
3
1
|
import pandas as pd
|
|
4
2
|
from django.apps import apps as django_apps
|
|
5
3
|
from django.db import models
|
|
@@ -8,7 +6,7 @@ from django.db import models
|
|
|
8
6
|
def refresh_model_from_dataframe(
|
|
9
7
|
df: pd.DataFrame,
|
|
10
8
|
model: str | None = None,
|
|
11
|
-
model_cls:
|
|
9
|
+
model_cls: type[models.Model] | None = None,
|
|
12
10
|
columns: list[str] | None = None,
|
|
13
11
|
) -> None:
|
|
14
12
|
columns = columns or list(df.columns)
|
edc_pdutils/utils/table_names.py
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import Type
|
|
4
|
-
|
|
5
3
|
from ..database import Database
|
|
6
4
|
|
|
7
5
|
|
|
@@ -9,7 +7,7 @@ def get_table_names(
|
|
|
9
7
|
app_label: str,
|
|
10
8
|
with_columns: list[str] | None = None,
|
|
11
9
|
without_columns: list[str] | None = None,
|
|
12
|
-
db_cls:
|
|
10
|
+
db_cls: type[Database] | None = None,
|
|
13
11
|
) -> list[str]:
|
|
14
12
|
"""Returns a list of table names for this app_label."""
|
|
15
13
|
db = (db_cls or Database)()
|
|
@@ -28,7 +26,7 @@ def get_model_names(
|
|
|
28
26
|
app_label: str,
|
|
29
27
|
with_columns: list[str] | None = None,
|
|
30
28
|
without_columns: list[str] | None = None,
|
|
31
|
-
db_cls:
|
|
29
|
+
db_cls: type[Database] | None = None,
|
|
32
30
|
exclude_historical: bool | None = None,
|
|
33
31
|
exclude_views: bool | None = None,
|
|
34
32
|
) -> list[str]:
|
edc_pdutils/utils/undash.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Tuple
|
|
2
|
-
|
|
3
1
|
from django import forms
|
|
4
2
|
from django.contrib import admin
|
|
5
3
|
from django_audit_fields.admin import audit_fieldset_tuple
|
|
@@ -30,14 +28,14 @@ class AssignmentAdmin(ModelAdminMixin, admin.ModelAdmin):
|
|
|
30
28
|
audit_fieldset_tuple,
|
|
31
29
|
)
|
|
32
30
|
|
|
33
|
-
list_display:
|
|
31
|
+
list_display: tuple[str, ...] = (
|
|
34
32
|
"name",
|
|
35
33
|
"display_name",
|
|
36
34
|
"created",
|
|
37
35
|
"modified",
|
|
38
36
|
)
|
|
39
37
|
|
|
40
|
-
search_fields:
|
|
38
|
+
search_fields: tuple[str, ...] = ("name", "display_name")
|
|
41
39
|
|
|
42
40
|
def get_readonly_fields(self, request, obj=None):
|
|
43
41
|
if obj:
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Tuple
|
|
2
|
-
|
|
3
1
|
from django.contrib import admin
|
|
4
2
|
from django_audit_fields.admin import audit_fieldset_tuple
|
|
5
3
|
|
|
@@ -34,5 +32,5 @@ class DosageGuidelineAdmin(ModelAdminMixin, admin.ModelAdmin):
|
|
|
34
32
|
audit_fieldset_tuple,
|
|
35
33
|
)
|
|
36
34
|
|
|
37
|
-
list_display:
|
|
38
|
-
search_fields:
|
|
35
|
+
list_display: tuple[str, ...] = ("__str__", "modified", "user_modified")
|
|
36
|
+
search_fields: tuple[str, ...] = ("medication__name",)
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Tuple
|
|
2
|
-
|
|
3
1
|
from django.contrib import admin
|
|
4
2
|
from django_audit_fields.admin import audit_fieldset_tuple
|
|
5
3
|
|
|
@@ -53,7 +51,7 @@ class FormulationAdmin(ModelAdminMixin, admin.ModelAdmin):
|
|
|
53
51
|
"route": admin.VERTICAL,
|
|
54
52
|
}
|
|
55
53
|
|
|
56
|
-
list_filter:
|
|
54
|
+
list_filter: tuple[str, ...] = (
|
|
57
55
|
"imp",
|
|
58
56
|
"strength",
|
|
59
57
|
"units",
|
|
@@ -70,6 +68,6 @@ class FormulationAdmin(ModelAdminMixin, admin.ModelAdmin):
|
|
|
70
68
|
"route",
|
|
71
69
|
)
|
|
72
70
|
|
|
73
|
-
search_fields:
|
|
71
|
+
search_fields: tuple[str, ...] = ("medication__name",)
|
|
74
72
|
|
|
75
|
-
ordering:
|
|
73
|
+
ordering: tuple[str, ...] = ("medication__name",)
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Tuple
|
|
2
|
-
|
|
3
1
|
from django.contrib import admin
|
|
4
2
|
from django_audit_fields.admin import audit_fieldset_tuple
|
|
5
3
|
|
|
@@ -23,8 +21,8 @@ class MedicationAdmin(ModelAdminMixin, admin.ModelAdmin):
|
|
|
23
21
|
audit_fieldset_tuple,
|
|
24
22
|
)
|
|
25
23
|
|
|
26
|
-
list_display:
|
|
24
|
+
list_display: tuple[str, ...] = ("name", "display_name", "created", "modified")
|
|
27
25
|
|
|
28
|
-
search_fields:
|
|
26
|
+
search_fields: tuple[str, ...] = ("name",)
|
|
29
27
|
|
|
30
|
-
ordering:
|
|
28
|
+
ordering: tuple[str, ...] = ("name",)
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Tuple
|
|
2
|
-
|
|
3
1
|
from django.conf import settings
|
|
4
2
|
from django.contrib import admin
|
|
5
3
|
from django.template.loader import render_to_string
|
|
@@ -21,7 +19,7 @@ from ..model_admin_mixin import ModelAdminMixin
|
|
|
21
19
|
class RxRefillAdmin(ModelAdminMixin, admin.ModelAdmin):
|
|
22
20
|
show_object_tools = True
|
|
23
21
|
|
|
24
|
-
ordering:
|
|
22
|
+
ordering: tuple[str, ...] = ("refill_start_datetime",)
|
|
25
23
|
|
|
26
24
|
autocomplete_fields = ["dosage_guideline", "formulation"]
|
|
27
25
|
|
|
@@ -65,7 +63,7 @@ class RxRefillAdmin(ModelAdminMixin, admin.ModelAdmin):
|
|
|
65
63
|
audit_fieldset_tuple,
|
|
66
64
|
)
|
|
67
65
|
|
|
68
|
-
list_display:
|
|
66
|
+
list_display: tuple[str, ...] = (
|
|
69
67
|
"subject_identifier",
|
|
70
68
|
"dashboard",
|
|
71
69
|
"duration",
|
|
@@ -79,7 +77,7 @@ class RxRefillAdmin(ModelAdminMixin, admin.ModelAdmin):
|
|
|
79
77
|
"verified_datetime",
|
|
80
78
|
)
|
|
81
79
|
|
|
82
|
-
list_filter:
|
|
80
|
+
list_filter: tuple[str, ...] = (
|
|
83
81
|
"active",
|
|
84
82
|
"refill_start_datetime",
|
|
85
83
|
"refill_end_datetime",
|
|
@@ -89,7 +87,7 @@ class RxRefillAdmin(ModelAdminMixin, admin.ModelAdmin):
|
|
|
89
87
|
"site",
|
|
90
88
|
)
|
|
91
89
|
|
|
92
|
-
search_fields:
|
|
90
|
+
search_fields: tuple[str, ...] = (
|
|
93
91
|
"id",
|
|
94
92
|
"site__id",
|
|
95
93
|
"rx__id",
|
|
@@ -178,7 +176,7 @@ class RxRefillInlineAdmin(admin.StackedInline):
|
|
|
178
176
|
|
|
179
177
|
model = RxRefill
|
|
180
178
|
|
|
181
|
-
fields:
|
|
179
|
+
fields: tuple[str, ...] = (
|
|
182
180
|
"dosage_guideline",
|
|
183
181
|
"formulation",
|
|
184
182
|
"refill_start_datetime",
|
|
@@ -189,8 +187,8 @@ class RxRefillInlineAdmin(admin.StackedInline):
|
|
|
189
187
|
"frequency_units",
|
|
190
188
|
)
|
|
191
189
|
|
|
192
|
-
search_fields:
|
|
190
|
+
search_fields: tuple[str, ...] = "dosage_guideline__medication__name"
|
|
193
191
|
|
|
194
|
-
ordering:
|
|
192
|
+
ordering: tuple[str, ...] = ("refill_start_datetime",)
|
|
195
193
|
|
|
196
194
|
extra = 0
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Tuple
|
|
2
|
-
|
|
3
1
|
from django.contrib import admin
|
|
4
2
|
from django_audit_fields.admin import audit_fieldset_tuple
|
|
5
3
|
|
|
@@ -67,7 +65,7 @@ class LotAdmin(ModelAdminMixin, SimpleHistoryAdmin):
|
|
|
67
65
|
audit_fieldset_tuple,
|
|
68
66
|
)
|
|
69
67
|
|
|
70
|
-
list_filter:
|
|
68
|
+
list_filter: tuple[str, ...] = (
|
|
71
69
|
"lot_no",
|
|
72
70
|
"expiration_date",
|
|
73
71
|
"product",
|
|
@@ -77,7 +75,7 @@ class LotAdmin(ModelAdminMixin, SimpleHistoryAdmin):
|
|
|
77
75
|
"modified",
|
|
78
76
|
)
|
|
79
77
|
|
|
80
|
-
list_display:
|
|
78
|
+
list_display: tuple[str, ...] = (
|
|
81
79
|
"lot_no",
|
|
82
80
|
"expiration_date",
|
|
83
81
|
"product",
|
|
@@ -86,11 +84,11 @@ class LotAdmin(ModelAdminMixin, SimpleHistoryAdmin):
|
|
|
86
84
|
"created",
|
|
87
85
|
"modified",
|
|
88
86
|
)
|
|
89
|
-
radio_fields:
|
|
87
|
+
radio_fields: tuple[str, ...] = {"assignment": admin.VERTICAL}
|
|
90
88
|
|
|
91
|
-
search_fields:
|
|
89
|
+
search_fields: tuple[str, ...] = ("lot_no",)
|
|
92
90
|
|
|
93
|
-
ordering:
|
|
91
|
+
ordering: tuple[str, ...] = ("-expiration_date",)
|
|
94
92
|
|
|
95
93
|
def get_readonly_fields(self, request, obj=None):
|
|
96
94
|
# if obj:
|
|
@@ -80,7 +80,7 @@ class OrderAdmin(ModelAdminMixin, SimpleHistoryAdmin):
|
|
|
80
80
|
if obj.item_count > OrderItem.objects.filter(order=obj).count():
|
|
81
81
|
url = reverse("edc_pharmacy_admin:edc_pharmacy_orderitem_add")
|
|
82
82
|
next_url = "edc_pharmacy_admin:edc_pharmacy_order_changelist"
|
|
83
|
-
url = f"{url}?next={next_url}&order={
|
|
83
|
+
url = f"{url}?next={next_url}&order={obj.id!s}&q={obj.order_identifier!s}"
|
|
84
84
|
context = dict(url=url, label="Add order item")
|
|
85
85
|
add_order_items_button = render_to_string(
|
|
86
86
|
"edc_pharmacy/stock/items_as_button.html", context=context
|
|
@@ -112,7 +112,7 @@ class OrderAdmin(ModelAdminMixin, SimpleHistoryAdmin):
|
|
|
112
112
|
pass
|
|
113
113
|
else:
|
|
114
114
|
url = reverse("edc_pharmacy_admin:edc_pharmacy_receive_changelist")
|
|
115
|
-
url = f"{url}?q={
|
|
115
|
+
url = f"{url}?q={rcv_obj.receive_identifier!s}"
|
|
116
116
|
context = dict(url=url, label=rcv_obj.receive_identifier, title="Receive #")
|
|
117
117
|
return render_to_string("edc_pharmacy/stock/items_as_link.html", context=context)
|
|
118
118
|
return None
|
|
@@ -167,7 +167,7 @@ class OrderItemAdmin(ModelAdminMixin, SimpleHistoryAdmin):
|
|
|
167
167
|
def get_status_label(self, obj: OrderItem) -> tuple[str, str]:
|
|
168
168
|
if obj.unit_qty == 0:
|
|
169
169
|
return RECEIVED, _("Received")
|
|
170
|
-
|
|
170
|
+
if obj.unit_qty == obj.unit_qty_ordered:
|
|
171
171
|
return NEW, _("New")
|
|
172
172
|
return PARTIAL, _("Partial")
|
|
173
173
|
|
|
@@ -202,7 +202,7 @@ class OrderItemAdmin(ModelAdminMixin, SimpleHistoryAdmin):
|
|
|
202
202
|
def render_start_receiving_button(obj: OrderItem) -> str:
|
|
203
203
|
url = reverse("edc_pharmacy_admin:edc_pharmacy_receive_add")
|
|
204
204
|
next_url = "edc_pharmacy_admin:edc_pharmacy_orderitem_changelist"
|
|
205
|
-
url = f"{url}?next={next_url}&q={
|
|
205
|
+
url = f"{url}?next={next_url}&q={obj.order.id!s}&order={obj.order.id!s}"
|
|
206
206
|
context = dict(
|
|
207
207
|
url=url,
|
|
208
208
|
label=_("Start Receiving"),
|
|
@@ -216,7 +216,7 @@ class OrderItemAdmin(ModelAdminMixin, SimpleHistoryAdmin):
|
|
|
216
216
|
@staticmethod
|
|
217
217
|
def render_receive_changelist_link(receive: Receive) -> str:
|
|
218
218
|
url = reverse("edc_pharmacy_admin:edc_pharmacy_receive_changelist")
|
|
219
|
-
url = f"{url}?q={
|
|
219
|
+
url = f"{url}?q={receive.receive_identifier!s}"
|
|
220
220
|
context = dict(url=url, label=receive.receive_identifier, title=_("Receive"))
|
|
221
221
|
return render_to_string(
|
|
222
222
|
"edc_pharmacy/stock/items_as_link.html",
|
|
@@ -228,8 +228,8 @@ class OrderItemAdmin(ModelAdminMixin, SimpleHistoryAdmin):
|
|
|
228
228
|
url = reverse("edc_pharmacy_admin:edc_pharmacy_receiveitem_add")
|
|
229
229
|
next_url = "edc_pharmacy_admin:edc_pharmacy_orderitem_changelist"
|
|
230
230
|
url = (
|
|
231
|
-
f"{url}?next={next_url}&order_item={
|
|
232
|
-
f"&receive={
|
|
231
|
+
f"{url}?next={next_url}&order_item={obj.id!s}&q={obj.order.id!s}"
|
|
232
|
+
f"&receive={receive.id!s}&container={obj.container.id!s}"
|
|
233
233
|
)
|
|
234
234
|
context = dict(
|
|
235
235
|
url=url,
|
|
@@ -245,7 +245,7 @@ class OrderItemAdmin(ModelAdminMixin, SimpleHistoryAdmin):
|
|
|
245
245
|
status, status_label = self.get_status_label(obj)
|
|
246
246
|
if status != NEW:
|
|
247
247
|
url = reverse("edc_pharmacy_admin:edc_pharmacy_receiveitem_changelist")
|
|
248
|
-
url = f"{url}?q={
|
|
248
|
+
url = f"{url}?q={obj.pk!s}"
|
|
249
249
|
context = dict(url=url, label=status_label, title=_("Go to received items"))
|
|
250
250
|
return render_to_string("edc_pharmacy/stock/items_as_link.html", context=context)
|
|
251
251
|
return None
|
|
@@ -105,7 +105,7 @@ class ReceiveAdmin(ModelAdminMixin, SimpleHistoryAdmin):
|
|
|
105
105
|
@admin.display(description="Order #")
|
|
106
106
|
def order_changelist(self, obj):
|
|
107
107
|
url = reverse("edc_pharmacy_admin:edc_pharmacy_order_changelist")
|
|
108
|
-
url = f"{url}?q={
|
|
108
|
+
url = f"{url}?q={obj.order.order_identifier!s}"
|
|
109
109
|
context = dict(url=url, label=obj.order.order_identifier, title="Back to order")
|
|
110
110
|
return render_to_string("edc_pharmacy/stock/items_as_link.html", context=context)
|
|
111
111
|
|
|
@@ -122,7 +122,7 @@ class ReceiveItemAdmin(ModelAdminMixin, SimpleHistoryAdmin):
|
|
|
122
122
|
@admin.display(description="Order #")
|
|
123
123
|
def order_changelist(self, obj):
|
|
124
124
|
url = reverse("edc_pharmacy_admin:edc_pharmacy_order_changelist")
|
|
125
|
-
url = f"{url}?q={
|
|
125
|
+
url = f"{url}?q={obj.order_item.order.order_identifier!s}"
|
|
126
126
|
context = dict(
|
|
127
127
|
url=url, label=obj.order_item.order.order_identifier, title="Back to order"
|
|
128
128
|
)
|
|
@@ -131,7 +131,7 @@ class ReceiveItemAdmin(ModelAdminMixin, SimpleHistoryAdmin):
|
|
|
131
131
|
@admin.display(description="Order item #")
|
|
132
132
|
def order_items_changelist(self, obj):
|
|
133
133
|
url = reverse("edc_pharmacy_admin:edc_pharmacy_orderitem_changelist")
|
|
134
|
-
url = f"{url}?q={
|
|
134
|
+
url = f"{url}?q={obj.order_item.id!s}"
|
|
135
135
|
context = dict(
|
|
136
136
|
url=url,
|
|
137
137
|
label=obj.order_item.order_item_identifier,
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
|
|
3
1
|
from celery.result import AsyncResult
|
|
4
2
|
from celery.states import SUCCESS
|
|
5
3
|
from django.contrib import admin
|
|
@@ -46,16 +44,16 @@ class StatusListFilter(admin.SimpleListFilter):
|
|
|
46
44
|
.exclude(item_count=0)
|
|
47
45
|
.distinct()
|
|
48
46
|
)
|
|
49
|
-
|
|
47
|
+
if self.value() == COMPLETE:
|
|
50
48
|
return (
|
|
51
49
|
queryset.filter(cancel__isnull=True)
|
|
52
50
|
.exclude(stockrequestitem__allocation__isnull=True)
|
|
53
51
|
.exclude(item_count=0)
|
|
54
52
|
.distinct()
|
|
55
53
|
)
|
|
56
|
-
|
|
54
|
+
if self.value() == CANCELLED:
|
|
57
55
|
return queryset.filter(cancel__isnull=False)
|
|
58
|
-
|
|
56
|
+
if self.value() == "ZERO":
|
|
59
57
|
return queryset.filter(item_count=0, cancel__isnull=True)
|
|
60
58
|
return None
|
|
61
59
|
|
|
@@ -148,7 +146,7 @@ class StockRequestAdmin(ModelAdminMixin, SimpleHistoryAdmin):
|
|
|
148
146
|
|
|
149
147
|
readonly_fields = ("item_count",)
|
|
150
148
|
|
|
151
|
-
def redirect_url(self, request, obj, post_url_continue=None) ->
|
|
149
|
+
def redirect_url(self, request, obj, post_url_continue=None) -> str | None:
|
|
152
150
|
"""Redirect to the review page immediately after saving model."""
|
|
153
151
|
redirect_url = super().redirect_url(request, obj, post_url_continue)
|
|
154
152
|
if obj.cancel == "CANCEL":
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from decimal import Decimal
|
|
2
|
-
from typing import Any
|
|
2
|
+
from typing import Any
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class DosageError(Exception):
|
|
@@ -9,9 +9,9 @@ class DosageError(Exception):
|
|
|
9
9
|
class DosageCalculator:
|
|
10
10
|
def __init__(
|
|
11
11
|
self,
|
|
12
|
-
dosage_guideline:
|
|
13
|
-
formulation:
|
|
14
|
-
weight_in_kgs:
|
|
12
|
+
dosage_guideline: Any | None = None,
|
|
13
|
+
formulation: Any | None = None,
|
|
14
|
+
weight_in_kgs: float | Decimal | None = None,
|
|
15
15
|
) -> None:
|
|
16
16
|
self.dosage_guideline = dosage_guideline
|
|
17
17
|
self.formulation = formulation
|
|
@@ -110,11 +110,10 @@ class StudyMedicationFormValidator(CrfFormValidator):
|
|
|
110
110
|
def medication(self) -> Medication:
|
|
111
111
|
if self.formulation:
|
|
112
112
|
return self.formulation.medication
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
)
|
|
113
|
+
self.raise_validation_error(
|
|
114
|
+
{"__all__": "Need the formulation to look up the prescription."},
|
|
115
|
+
INVALID_ERROR,
|
|
116
|
+
)
|
|
118
117
|
|
|
119
118
|
@property
|
|
120
119
|
def next_appointment(self) -> Appointment | None:
|
|
@@ -154,9 +153,10 @@ class StudyMedicationFormValidator(CrfFormValidator):
|
|
|
154
153
|
"Subject is not receiving study medication. Refill end date "
|
|
155
154
|
"and time must exactly match refill start date and time."
|
|
156
155
|
)
|
|
157
|
-
if
|
|
158
|
-
self.
|
|
159
|
-
|
|
156
|
+
if (
|
|
157
|
+
not self.refill_end_datetime
|
|
158
|
+
or self.refill_start_datetime != self.refill_end_datetime
|
|
159
|
+
):
|
|
160
160
|
self.raise_validation_error({"refill_end_datetime": error_msg}, INVALID_ERROR)
|
|
161
161
|
|
|
162
162
|
if (
|
|
@@ -6,7 +6,6 @@ from ...models import Allocation, StockRequest
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class StockRequestForm(forms.ModelForm):
|
|
9
|
-
|
|
10
9
|
def clean(self):
|
|
11
10
|
cleaned_data = super().clean()
|
|
12
11
|
|
|
@@ -41,8 +40,7 @@ class StockRequestForm(forms.ModelForm):
|
|
|
41
40
|
raise forms.ValidationError(
|
|
42
41
|
{
|
|
43
42
|
"excluded_subject_identifiers": (
|
|
44
|
-
"Not all subject identifiers are valid. "
|
|
45
|
-
"Type one subject per line."
|
|
43
|
+
"Not all subject identifiers are valid. Type one subject per line."
|
|
46
44
|
)
|
|
47
45
|
}
|
|
48
46
|
)
|
|
@@ -64,7 +62,7 @@ class StockRequestForm(forms.ModelForm):
|
|
|
64
62
|
|
|
65
63
|
if not self.instance.id and cleaned_data.get("cancel") == "CANCEL":
|
|
66
64
|
raise forms.ValidationError("Leave this blank")
|
|
67
|
-
|
|
65
|
+
if cleaned_data.get("cancel") == "CANCEL":
|
|
68
66
|
if Allocation.objects.filter(
|
|
69
67
|
stock_request_item__stock_request=self.instance
|
|
70
68
|
).exists():
|