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
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import csv
|
|
2
|
-
import os
|
|
3
2
|
import uuid
|
|
3
|
+
from pathlib import Path
|
|
4
4
|
|
|
5
5
|
from django.apps import apps as django_apps
|
|
6
6
|
from django.core.exceptions import ValidationError
|
|
7
|
-
|
|
8
|
-
from edc_utils import get_utcnow
|
|
7
|
+
from django.utils import timezone
|
|
9
8
|
|
|
10
9
|
from ..utils import get_export_folder
|
|
11
10
|
from .file_history_updater import FileHistoryUpdater
|
|
@@ -17,11 +16,11 @@ class ModelExporterError(Exception):
|
|
|
17
16
|
pass
|
|
18
17
|
|
|
19
18
|
|
|
20
|
-
class ModelExporterInvalidLookup(Exception):
|
|
19
|
+
class ModelExporterInvalidLookup(Exception): # noqa: N818
|
|
21
20
|
pass
|
|
22
21
|
|
|
23
22
|
|
|
24
|
-
class ModelExporterUnknownField(ValidationError):
|
|
23
|
+
class ModelExporterUnknownField(ValidationError): # noqa: N818
|
|
25
24
|
pass
|
|
26
25
|
|
|
27
26
|
|
|
@@ -40,14 +39,14 @@ class ModelExporter:
|
|
|
40
39
|
value_getter_cls = ValueGetter
|
|
41
40
|
additional_values_cls = AdditionalValues
|
|
42
41
|
|
|
43
|
-
export_fields =
|
|
42
|
+
export_fields = (
|
|
44
43
|
"export_uuid",
|
|
45
44
|
"timestamp",
|
|
46
45
|
"export_datetime",
|
|
47
46
|
"export_change_type",
|
|
48
|
-
|
|
49
|
-
required_fields =
|
|
50
|
-
audit_fields =
|
|
47
|
+
)
|
|
48
|
+
required_fields = ("subject_identifier", "report_datetime")
|
|
49
|
+
audit_fields = (
|
|
51
50
|
"hostname_created",
|
|
52
51
|
"hostname_modified",
|
|
53
52
|
"created",
|
|
@@ -55,7 +54,7 @@ class ModelExporter:
|
|
|
55
54
|
"user_created",
|
|
56
55
|
"user_modified",
|
|
57
56
|
"revision",
|
|
58
|
-
|
|
57
|
+
)
|
|
59
58
|
|
|
60
59
|
def __init__(
|
|
61
60
|
self,
|
|
@@ -103,7 +102,10 @@ class ModelExporter:
|
|
|
103
102
|
if f in self.export_fields or f in self.audit_fields or f in self.required_fields:
|
|
104
103
|
self._field_names.pop(self._field_names.index(f))
|
|
105
104
|
self._field_names = (
|
|
106
|
-
self.export_fields
|
|
105
|
+
*self.export_fields,
|
|
106
|
+
*self.required_fields,
|
|
107
|
+
*self.field_names,
|
|
108
|
+
*self.audit_fields,
|
|
107
109
|
)
|
|
108
110
|
|
|
109
111
|
@property
|
|
@@ -117,13 +119,13 @@ class ModelExporter:
|
|
|
117
119
|
self._model_cls = self.queryset.model
|
|
118
120
|
return self._model_cls
|
|
119
121
|
|
|
120
|
-
def export(self, queryset=None):
|
|
122
|
+
def export(self, queryset=None) -> Path:
|
|
121
123
|
"""Writes the export file and returns the file name."""
|
|
122
124
|
self.queryset = queryset or self.queryset
|
|
123
|
-
exported_datetime =
|
|
125
|
+
exported_datetime = timezone.now()
|
|
124
126
|
filename = self.get_filename(exported_datetime)
|
|
125
|
-
path =
|
|
126
|
-
with open(
|
|
127
|
+
path = get_export_folder() / filename
|
|
128
|
+
with path.open("w") as f:
|
|
127
129
|
csv_writer = csv.DictWriter(
|
|
128
130
|
f, fieldnames=self.field_names, delimiter=self.delimiter
|
|
129
131
|
)
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
from django.apps import apps as django_apps
|
|
2
2
|
from django.core import serializers
|
|
3
3
|
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
|
|
4
|
+
from django.utils import timezone
|
|
4
5
|
|
|
5
6
|
from edc_constants.constants import NEW
|
|
6
|
-
from edc_utils import get_utcnow
|
|
7
7
|
|
|
8
8
|
from ..constants import EXPORTED, INSERT, UPDATE
|
|
9
9
|
|
|
@@ -24,7 +24,7 @@ class ObjectHistoryCreator(Base):
|
|
|
24
24
|
def create(self, model_obj=None, change_type=None, using=None):
|
|
25
25
|
if not change_type:
|
|
26
26
|
change_type = self.get_change_type(model_obj=model_obj)
|
|
27
|
-
export_datetime =
|
|
27
|
+
export_datetime = timezone.now()
|
|
28
28
|
if model_obj._meta.proxy_for_model: # if proxy model, get main model
|
|
29
29
|
model_obj = model_obj._meta.proxy_for_model.objects.get(id=model_obj.id)
|
|
30
30
|
obj = self.model_cls.objects.using(using).create(
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
from django.db import models
|
|
2
2
|
from django.db.models import Index
|
|
3
3
|
from django.db.models.deletion import PROTECT
|
|
4
|
+
from django.utils import timezone
|
|
4
5
|
|
|
5
6
|
from edc_model.models import BaseUuidModel
|
|
6
7
|
from edc_sites.model_mixins import SiteModelMixin
|
|
7
|
-
from edc_utils import get_utcnow
|
|
8
8
|
|
|
9
9
|
from .data_request import DataRequest
|
|
10
10
|
|
|
@@ -12,15 +12,15 @@ from .data_request import DataRequest
|
|
|
12
12
|
class DataRequestHistory(SiteModelMixin, BaseUuidModel):
|
|
13
13
|
data_request = models.ForeignKey(DataRequest, on_delete=PROTECT)
|
|
14
14
|
|
|
15
|
-
archive_filename = models.CharField(max_length=200,
|
|
15
|
+
archive_filename = models.CharField(max_length=200, default="")
|
|
16
16
|
|
|
17
|
-
emailed_to = models.EmailField(
|
|
17
|
+
emailed_to = models.EmailField(default="")
|
|
18
18
|
|
|
19
19
|
emailed_datetime = models.DateTimeField(null=True)
|
|
20
20
|
|
|
21
21
|
summary = models.TextField(default="")
|
|
22
22
|
|
|
23
|
-
exported_datetime = models.DateTimeField(default=
|
|
23
|
+
exported_datetime = models.DateTimeField(default=timezone.now)
|
|
24
24
|
|
|
25
25
|
class Meta:
|
|
26
26
|
verbose_name = "Data Request History"
|
edc_export/utils.py
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import os
|
|
4
3
|
import re
|
|
5
4
|
from collections.abc import Iterable
|
|
5
|
+
from pathlib import Path
|
|
6
6
|
|
|
7
7
|
from django import forms
|
|
8
|
+
from django.conf import settings
|
|
8
9
|
from django.utils.html import format_html
|
|
9
10
|
|
|
10
11
|
from edc_protocol.research_protocol_config import ResearchProtocolConfig
|
|
@@ -13,15 +14,13 @@ from .constants import EXPORT_PII
|
|
|
13
14
|
from .exceptions import ExporterExportFolder
|
|
14
15
|
|
|
15
16
|
|
|
16
|
-
def get_export_folder() ->
|
|
17
|
-
from django.conf import settings
|
|
18
|
-
|
|
17
|
+
def get_export_folder() -> Path:
|
|
19
18
|
if path := getattr(settings, "EDC_EXPORT_EXPORT_FOLDER", None):
|
|
20
|
-
return
|
|
21
|
-
return
|
|
19
|
+
return Path(path).expanduser()
|
|
20
|
+
return Path(settings.MEDIA_ROOT) / "data_folder" / "export"
|
|
22
21
|
|
|
23
22
|
|
|
24
|
-
def get_base_dir() ->
|
|
23
|
+
def get_base_dir() -> Path:
|
|
25
24
|
"""Returns the base_dir used by, for example,
|
|
26
25
|
shutil.make_archive.
|
|
27
26
|
|
|
@@ -37,20 +36,16 @@ def get_base_dir() -> str:
|
|
|
37
36
|
"Invalid base_dir, invalid characters. Using `protocol_lower_name`. "
|
|
38
37
|
f"Got `{base_dir}`."
|
|
39
38
|
)
|
|
40
|
-
return base_dir
|
|
41
|
-
|
|
39
|
+
return Path(base_dir)
|
|
42
40
|
|
|
43
|
-
def get_upload_folder() -> str:
|
|
44
|
-
from django.conf import settings
|
|
45
41
|
|
|
42
|
+
def get_upload_folder() -> Path:
|
|
46
43
|
if path := getattr(settings, "EDC_EXPORT_UPLOAD_FOLDER", None):
|
|
47
|
-
return
|
|
48
|
-
return
|
|
44
|
+
return Path(path).expanduser()
|
|
45
|
+
return Path(settings.MEDIA_ROOT) / "data_folder" / "upload"
|
|
49
46
|
|
|
50
47
|
|
|
51
48
|
def get_export_pii_users() -> list[str]:
|
|
52
|
-
from django.conf import settings
|
|
53
|
-
|
|
54
49
|
return getattr(settings, "EDC_EXPORT_EXPORT_PII_USERS", [])
|
|
55
50
|
|
|
56
51
|
|
edc_facility/auths.py
CHANGED
|
@@ -2,6 +2,11 @@ from edc_auth.site_auths import site_auths
|
|
|
2
2
|
|
|
3
3
|
from .auth_objects import EDC_FACILITY, EDC_FACILITY_SUPER, EDC_FACILITY_VIEW, codenames
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
site_auths.add_group(*codenames, name=
|
|
5
|
+
|
|
6
|
+
def update_site_auths():
|
|
7
|
+
site_auths.add_group(*codenames, name=EDC_FACILITY_VIEW, view_only=True)
|
|
8
|
+
site_auths.add_group(*codenames, name=EDC_FACILITY, no_delete=True)
|
|
9
|
+
site_auths.add_group(*codenames, name=EDC_FACILITY_SUPER)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
update_site_auths()
|
edc_facility/facility.py
CHANGED
|
@@ -7,17 +7,17 @@ from zoneinfo import ZoneInfo
|
|
|
7
7
|
|
|
8
8
|
import arrow
|
|
9
9
|
from arrow import Arrow
|
|
10
|
-
from dateutil.
|
|
11
|
-
from dateutil.relativedelta import relativedelta
|
|
10
|
+
from dateutil.relativedelta import relativedelta, weekday
|
|
12
11
|
from django.conf import settings
|
|
12
|
+
from django.utils import timezone
|
|
13
13
|
|
|
14
|
-
from edc_utils import convert_php_dateformat,
|
|
14
|
+
from edc_utils import convert_php_dateformat, to_utc
|
|
15
15
|
|
|
16
16
|
from .exceptions import FacilityError
|
|
17
17
|
from .holidays import Holidays
|
|
18
18
|
|
|
19
19
|
if TYPE_CHECKING:
|
|
20
|
-
|
|
20
|
+
pass
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class Facility:
|
|
@@ -34,24 +34,19 @@ class Facility:
|
|
|
34
34
|
|
|
35
35
|
def __init__(
|
|
36
36
|
self,
|
|
37
|
-
name: str = None,
|
|
38
|
-
days: list = None,
|
|
39
|
-
slots: list[int] = None,
|
|
37
|
+
name: str | None = None,
|
|
38
|
+
days: list[weekday] | None = None,
|
|
39
|
+
slots: list[int] | None = None,
|
|
40
40
|
best_effort_available_datetime: datetime | None = None,
|
|
41
41
|
):
|
|
42
|
-
self.days =
|
|
42
|
+
self.days = days
|
|
43
43
|
self.name = name
|
|
44
44
|
if not name:
|
|
45
45
|
raise FacilityError(f"Name cannot be None. See {self!r}")
|
|
46
46
|
self.best_effort_available_datetime = (
|
|
47
47
|
True if best_effort_available_datetime is None else best_effort_available_datetime
|
|
48
48
|
)
|
|
49
|
-
for
|
|
50
|
-
try:
|
|
51
|
-
day.weekday
|
|
52
|
-
except AttributeError:
|
|
53
|
-
day = weekday(day)
|
|
54
|
-
self.days.append(day)
|
|
49
|
+
self.weekdays = [d.weekday for d in self.days]
|
|
55
50
|
self.slots = slots or [99999 for _ in self.days]
|
|
56
51
|
self.config = dict(zip([str(d) for d in self.days], self.slots, strict=False))
|
|
57
52
|
self.holidays = self.holiday_cls()
|
|
@@ -72,9 +67,9 @@ class Facility:
|
|
|
72
67
|
slots_per_day = 0
|
|
73
68
|
return slots_per_day
|
|
74
69
|
|
|
75
|
-
@property
|
|
76
|
-
def weekdays(self) -> list[int]:
|
|
77
|
-
|
|
70
|
+
# @property
|
|
71
|
+
# def weekdays(self) -> list[int]:
|
|
72
|
+
# return [d.weekday for d in self.days]
|
|
78
73
|
|
|
79
74
|
@staticmethod
|
|
80
75
|
def open_slot_on(arr) -> Arrow:
|
|
@@ -112,7 +107,7 @@ class Facility:
|
|
|
112
107
|
span_gt = [arw for arw in span if arw.date() > suggested_arr.date()]
|
|
113
108
|
arr_span = []
|
|
114
109
|
max_len = max(len(span_lt), len(span_gt))
|
|
115
|
-
for
|
|
110
|
+
for _ in range(0, max_len):
|
|
116
111
|
try:
|
|
117
112
|
item = span_lt.pop()
|
|
118
113
|
except IndexError:
|
|
@@ -135,7 +130,7 @@ class Facility:
|
|
|
135
130
|
reverse_delta=None,
|
|
136
131
|
taken_datetimes=None,
|
|
137
132
|
schedule_on_holidays=None,
|
|
138
|
-
|
|
133
|
+
**kwargs, # noqa: ARG002
|
|
139
134
|
):
|
|
140
135
|
"""Returns an arrow object for a datetime equal to or
|
|
141
136
|
close to the suggested datetime.
|
|
@@ -153,7 +148,7 @@ class Facility:
|
|
|
153
148
|
if suggested_datetime:
|
|
154
149
|
suggested_arr = arrow.Arrow.fromdatetime(suggested_datetime)
|
|
155
150
|
else:
|
|
156
|
-
suggested_arr = arrow.Arrow.fromdatetime(
|
|
151
|
+
suggested_arr = arrow.Arrow.fromdatetime(timezone.now())
|
|
157
152
|
arr_span_range, min_arr, max_arr = self.get_arr_span(
|
|
158
153
|
suggested_arr,
|
|
159
154
|
forward_delta,
|
|
@@ -185,7 +180,6 @@ class Facility:
|
|
|
185
180
|
f"{forward_delta.days} days of {formatted_date}. "
|
|
186
181
|
f"Facility is {self!r}."
|
|
187
182
|
)
|
|
188
|
-
|
|
183
|
+
return arrow.Arrow.fromdatetime(
|
|
189
184
|
datetime.combine(available_arr.date(), suggested_arr.time())
|
|
190
185
|
)
|
|
191
|
-
return available_arr
|
edc_facility/import_holidays.py
CHANGED
|
@@ -9,10 +9,10 @@ from typing import TYPE_CHECKING
|
|
|
9
9
|
from django.conf import settings
|
|
10
10
|
from django.core.exceptions import ObjectDoesNotExist
|
|
11
11
|
from django.db import transaction
|
|
12
|
+
from django.utils import timezone
|
|
12
13
|
from tqdm import tqdm
|
|
13
14
|
|
|
14
15
|
from edc_sites.site import sites
|
|
15
|
-
from edc_utils import get_utcnow
|
|
16
16
|
|
|
17
17
|
from .exceptions import HolidayFileNotFoundError, HolidayImportError
|
|
18
18
|
from .utils import get_holiday_model_cls
|
|
@@ -30,14 +30,14 @@ def import_holidays(verbose: bool | None = None, test: bool | None = None) -> No
|
|
|
30
30
|
if test:
|
|
31
31
|
import_for_tests(model_cls)
|
|
32
32
|
else:
|
|
33
|
-
path = settings.HOLIDAY_FILE
|
|
33
|
+
path = Path(settings.HOLIDAY_FILE)
|
|
34
34
|
try:
|
|
35
35
|
if not Path(path).exists():
|
|
36
36
|
raise HolidayFileNotFoundError(path)
|
|
37
|
-
except TypeError:
|
|
37
|
+
except TypeError as e:
|
|
38
38
|
raise HolidayImportError(
|
|
39
39
|
f"Invalid path importing holiday file. See settings.HOLIDAY_FILE. Got {path}."
|
|
40
|
-
)
|
|
40
|
+
) from e
|
|
41
41
|
if verbose:
|
|
42
42
|
sys.stdout.write(
|
|
43
43
|
f"\nImporting holidays from '{path}' into {model_cls._meta.label_lower}\n"
|
|
@@ -52,9 +52,9 @@ def import_holidays(verbose: bool | None = None, test: bool | None = None) -> No
|
|
|
52
52
|
sys.stdout.write("Done.\n")
|
|
53
53
|
|
|
54
54
|
|
|
55
|
-
def check_for_duplicates_in_file(path) -> list:
|
|
55
|
+
def check_for_duplicates_in_file(path: Path) -> list:
|
|
56
56
|
"""Returns a list of records."""
|
|
57
|
-
with open(
|
|
57
|
+
with path.open("r") as f:
|
|
58
58
|
reader = csv.DictReader(f, fieldnames=["local_date", "label", "country"])
|
|
59
59
|
recs = [(row["local_date"], row["country"]) for row in reader]
|
|
60
60
|
if len(recs) != len(list(set(recs))):
|
|
@@ -62,18 +62,18 @@ def check_for_duplicates_in_file(path) -> list:
|
|
|
62
62
|
return recs
|
|
63
63
|
|
|
64
64
|
|
|
65
|
-
def import_file(path:
|
|
66
|
-
with open(
|
|
65
|
+
def import_file(path: Path, recs: list, model_cls: Holiday):
|
|
66
|
+
with path.open("r") as f:
|
|
67
67
|
reader = csv.DictReader(f, fieldnames=["local_date", "label", "country"])
|
|
68
68
|
for index, row in tqdm(enumerate(reader), total=len(recs)):
|
|
69
69
|
if index == 0:
|
|
70
70
|
continue
|
|
71
71
|
try:
|
|
72
|
-
local_date = datetime.strptime(row["local_date"], "%Y-%m-%d").date()
|
|
72
|
+
local_date = datetime.strptime(row["local_date"], "%Y-%m-%d").date() # noqa: DTZ007
|
|
73
73
|
except ValueError as e:
|
|
74
74
|
raise HolidayImportError(
|
|
75
75
|
f"Invalid format when importing from {path}. Got '{e}'"
|
|
76
|
-
)
|
|
76
|
+
) from e
|
|
77
77
|
else:
|
|
78
78
|
try:
|
|
79
79
|
obj = model_cls.objects.get(country=row["country"], local_date=local_date)
|
|
@@ -87,7 +87,7 @@ def import_file(path: str, recs: list, model_cls: Holiday):
|
|
|
87
87
|
|
|
88
88
|
|
|
89
89
|
def import_for_tests(model_cls: type[Holiday]):
|
|
90
|
-
year =
|
|
90
|
+
year = timezone.now().year
|
|
91
91
|
country = sites.get_current_country()
|
|
92
92
|
if not country:
|
|
93
93
|
raise HolidayImportError(
|
|
@@ -112,11 +112,11 @@ def import_for_tests(model_cls: type[Holiday]):
|
|
|
112
112
|
if index == 0:
|
|
113
113
|
continue
|
|
114
114
|
try:
|
|
115
|
-
local_date = datetime.strptime(row[LOCAL_DATE], "%Y-%m-%d").date()
|
|
115
|
+
local_date = datetime.strptime(row[LOCAL_DATE], "%Y-%m-%d").date() # noqa: DTZ007
|
|
116
116
|
except ValueError as e:
|
|
117
117
|
raise HolidayImportError(
|
|
118
118
|
f"Invalid format when importing holidays (test). Got '{e}'"
|
|
119
|
-
)
|
|
119
|
+
) from e
|
|
120
120
|
else:
|
|
121
121
|
objs.append(
|
|
122
122
|
model_cls(country=row[COUNTRY], local_date=local_date, name=row[LABEL])
|
|
@@ -17,7 +17,8 @@ from django.db import migrations, models
|
|
|
17
17
|
import edc_facility.model_mixins
|
|
18
18
|
import edc_model_fields.fields.other_charfield
|
|
19
19
|
import edc_sites.models
|
|
20
|
-
import
|
|
20
|
+
import django.utils.timezone
|
|
21
|
+
import django.utils.timezone
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
class Migration(migrations.Migration):
|
|
@@ -46,14 +47,14 @@ class Migration(migrations.Migration):
|
|
|
46
47
|
"created",
|
|
47
48
|
models.DateTimeField(
|
|
48
49
|
blank=True,
|
|
49
|
-
default=
|
|
50
|
+
default=django.utils.timezone.now,
|
|
50
51
|
),
|
|
51
52
|
),
|
|
52
53
|
(
|
|
53
54
|
"modified",
|
|
54
55
|
models.DateTimeField(
|
|
55
56
|
blank=True,
|
|
56
|
-
default=
|
|
57
|
+
default=django.utils.timezone.now,
|
|
57
58
|
),
|
|
58
59
|
),
|
|
59
60
|
(
|
|
@@ -105,7 +106,7 @@ class Migration(migrations.Migration):
|
|
|
105
106
|
),
|
|
106
107
|
(
|
|
107
108
|
"report_datetime",
|
|
108
|
-
models.DateTimeField(default=
|
|
109
|
+
models.DateTimeField(default=django.utils.timezone.now),
|
|
109
110
|
),
|
|
110
111
|
("name", models.CharField(max_length=25, unique=True)),
|
|
111
112
|
(
|
|
@@ -265,14 +266,14 @@ class Migration(migrations.Migration):
|
|
|
265
266
|
"created",
|
|
266
267
|
models.DateTimeField(
|
|
267
268
|
blank=True,
|
|
268
|
-
default=
|
|
269
|
+
default=django.utils.timezone.now,
|
|
269
270
|
),
|
|
270
271
|
),
|
|
271
272
|
(
|
|
272
273
|
"modified",
|
|
273
274
|
models.DateTimeField(
|
|
274
275
|
blank=True,
|
|
275
|
-
default=
|
|
276
|
+
default=django.utils.timezone.now,
|
|
276
277
|
),
|
|
277
278
|
),
|
|
278
279
|
(
|
|
@@ -323,7 +324,7 @@ class Migration(migrations.Migration):
|
|
|
323
324
|
),
|
|
324
325
|
(
|
|
325
326
|
"report_datetime",
|
|
326
|
-
models.DateTimeField(default=
|
|
327
|
+
models.DateTimeField(default=django.utils.timezone.now),
|
|
327
328
|
),
|
|
328
329
|
("name", models.CharField(db_index=True, max_length=25)),
|
|
329
330
|
(
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Generated by Django 5.2.6 on 2025-09-17 16:53
|
|
2
|
+
|
|
3
|
+
import edc_model_fields.fields.other_charfield
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
|
|
9
|
+
dependencies = [
|
|
10
|
+
("edc_facility", "0015_alter_healthfacility_revision_and_more"),
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
operations = [
|
|
14
|
+
migrations.AlterField(
|
|
15
|
+
model_name="healthfacility",
|
|
16
|
+
name="device_created",
|
|
17
|
+
field=models.CharField(
|
|
18
|
+
blank=True, default="", max_length=10, verbose_name="Device created"
|
|
19
|
+
),
|
|
20
|
+
),
|
|
21
|
+
migrations.AlterField(
|
|
22
|
+
model_name="healthfacility",
|
|
23
|
+
name="device_modified",
|
|
24
|
+
field=models.CharField(
|
|
25
|
+
blank=True, default="", max_length=10, verbose_name="Device modified"
|
|
26
|
+
),
|
|
27
|
+
),
|
|
28
|
+
migrations.AlterField(
|
|
29
|
+
model_name="healthfacility",
|
|
30
|
+
name="health_facility_type_other",
|
|
31
|
+
field=edc_model_fields.fields.other_charfield.OtherCharField(
|
|
32
|
+
blank=True,
|
|
33
|
+
default="",
|
|
34
|
+
max_length=35,
|
|
35
|
+
verbose_name="If other, please specify ...",
|
|
36
|
+
),
|
|
37
|
+
),
|
|
38
|
+
migrations.AlterField(
|
|
39
|
+
model_name="healthfacility",
|
|
40
|
+
name="locale_created",
|
|
41
|
+
field=models.CharField(
|
|
42
|
+
blank=True,
|
|
43
|
+
default="",
|
|
44
|
+
help_text="Auto-updated by Modeladmin",
|
|
45
|
+
max_length=10,
|
|
46
|
+
verbose_name="Locale created",
|
|
47
|
+
),
|
|
48
|
+
),
|
|
49
|
+
migrations.AlterField(
|
|
50
|
+
model_name="healthfacility",
|
|
51
|
+
name="locale_modified",
|
|
52
|
+
field=models.CharField(
|
|
53
|
+
blank=True,
|
|
54
|
+
default="",
|
|
55
|
+
help_text="Auto-updated by Modeladmin",
|
|
56
|
+
max_length=10,
|
|
57
|
+
verbose_name="Locale modified",
|
|
58
|
+
),
|
|
59
|
+
),
|
|
60
|
+
migrations.AlterField(
|
|
61
|
+
model_name="healthfacility",
|
|
62
|
+
name="notes",
|
|
63
|
+
field=models.TextField(blank=True, default=""),
|
|
64
|
+
),
|
|
65
|
+
migrations.AlterField(
|
|
66
|
+
model_name="healthfacilitytypes",
|
|
67
|
+
name="extra_value",
|
|
68
|
+
field=models.CharField(default="", max_length=250),
|
|
69
|
+
),
|
|
70
|
+
migrations.AlterField(
|
|
71
|
+
model_name="healthfacilitytypes",
|
|
72
|
+
name="field_name",
|
|
73
|
+
field=models.CharField(
|
|
74
|
+
blank=True,
|
|
75
|
+
default="",
|
|
76
|
+
editable=False,
|
|
77
|
+
help_text="Not required",
|
|
78
|
+
max_length=25,
|
|
79
|
+
),
|
|
80
|
+
),
|
|
81
|
+
migrations.AlterField(
|
|
82
|
+
model_name="healthfacilitytypes",
|
|
83
|
+
name="plural_name",
|
|
84
|
+
field=models.CharField(
|
|
85
|
+
default="", max_length=250, verbose_name="Plural name"
|
|
86
|
+
),
|
|
87
|
+
),
|
|
88
|
+
migrations.AlterField(
|
|
89
|
+
model_name="historicalhealthfacility",
|
|
90
|
+
name="device_created",
|
|
91
|
+
field=models.CharField(
|
|
92
|
+
blank=True, default="", max_length=10, verbose_name="Device created"
|
|
93
|
+
),
|
|
94
|
+
),
|
|
95
|
+
migrations.AlterField(
|
|
96
|
+
model_name="historicalhealthfacility",
|
|
97
|
+
name="device_modified",
|
|
98
|
+
field=models.CharField(
|
|
99
|
+
blank=True, default="", max_length=10, verbose_name="Device modified"
|
|
100
|
+
),
|
|
101
|
+
),
|
|
102
|
+
migrations.AlterField(
|
|
103
|
+
model_name="historicalhealthfacility",
|
|
104
|
+
name="health_facility_type_other",
|
|
105
|
+
field=edc_model_fields.fields.other_charfield.OtherCharField(
|
|
106
|
+
blank=True,
|
|
107
|
+
default="",
|
|
108
|
+
max_length=35,
|
|
109
|
+
verbose_name="If other, please specify ...",
|
|
110
|
+
),
|
|
111
|
+
),
|
|
112
|
+
migrations.AlterField(
|
|
113
|
+
model_name="historicalhealthfacility",
|
|
114
|
+
name="locale_created",
|
|
115
|
+
field=models.CharField(
|
|
116
|
+
blank=True,
|
|
117
|
+
default="",
|
|
118
|
+
help_text="Auto-updated by Modeladmin",
|
|
119
|
+
max_length=10,
|
|
120
|
+
verbose_name="Locale created",
|
|
121
|
+
),
|
|
122
|
+
),
|
|
123
|
+
migrations.AlterField(
|
|
124
|
+
model_name="historicalhealthfacility",
|
|
125
|
+
name="locale_modified",
|
|
126
|
+
field=models.CharField(
|
|
127
|
+
blank=True,
|
|
128
|
+
default="",
|
|
129
|
+
help_text="Auto-updated by Modeladmin",
|
|
130
|
+
max_length=10,
|
|
131
|
+
verbose_name="Locale modified",
|
|
132
|
+
),
|
|
133
|
+
),
|
|
134
|
+
migrations.AlterField(
|
|
135
|
+
model_name="historicalhealthfacility",
|
|
136
|
+
name="notes",
|
|
137
|
+
field=models.TextField(blank=True, default=""),
|
|
138
|
+
),
|
|
139
|
+
]
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Generated by Django 5.2.6 on 2025-09-18 00:24
|
|
2
|
+
|
|
3
|
+
import django.utils.timezone
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
|
|
9
|
+
dependencies = [
|
|
10
|
+
("edc_facility", "0016_alter_healthfacility_device_created_and_more"),
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
operations = [
|
|
14
|
+
migrations.AlterField(
|
|
15
|
+
model_name="healthfacility",
|
|
16
|
+
name="gps",
|
|
17
|
+
field=models.CharField(
|
|
18
|
+
blank=True,
|
|
19
|
+
default="",
|
|
20
|
+
help_text="copy and paste directly from google maps",
|
|
21
|
+
max_length=50,
|
|
22
|
+
),
|
|
23
|
+
),
|
|
24
|
+
migrations.AlterField(
|
|
25
|
+
model_name="healthfacility",
|
|
26
|
+
name="report_datetime",
|
|
27
|
+
field=models.DateTimeField(default=django.utils.timezone.now),
|
|
28
|
+
),
|
|
29
|
+
migrations.AlterField(
|
|
30
|
+
model_name="healthfacility",
|
|
31
|
+
name="title",
|
|
32
|
+
field=models.CharField(blank=True, default="", max_length=150),
|
|
33
|
+
),
|
|
34
|
+
migrations.AlterField(
|
|
35
|
+
model_name="historicalhealthfacility",
|
|
36
|
+
name="gps",
|
|
37
|
+
field=models.CharField(
|
|
38
|
+
blank=True,
|
|
39
|
+
default="",
|
|
40
|
+
help_text="copy and paste directly from google maps",
|
|
41
|
+
max_length=50,
|
|
42
|
+
),
|
|
43
|
+
),
|
|
44
|
+
migrations.AlterField(
|
|
45
|
+
model_name="historicalhealthfacility",
|
|
46
|
+
name="report_datetime",
|
|
47
|
+
field=models.DateTimeField(default=django.utils.timezone.now),
|
|
48
|
+
),
|
|
49
|
+
migrations.AlterField(
|
|
50
|
+
model_name="historicalhealthfacility",
|
|
51
|
+
name="title",
|
|
52
|
+
field=models.CharField(blank=True, default="", max_length=150),
|
|
53
|
+
),
|
|
54
|
+
]
|