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.

Files changed (495) hide show
  1. {clinicedc-2.0.6.dist-info → clinicedc-2.0.8.dist-info}/METADATA +2 -2
  2. {clinicedc-2.0.6.dist-info → clinicedc-2.0.8.dist-info}/RECORD +489 -441
  3. {clinicedc-2.0.6.dist-info → clinicedc-2.0.8.dist-info}/WHEEL +1 -1
  4. edc_action_item/action.py +1 -1
  5. edc_action_item/action_item_notification.py +2 -2
  6. edc_action_item/auths.py +37 -32
  7. edc_action_item/create_action_item.py +1 -1
  8. edc_action_item/decorators.py +1 -1
  9. edc_action_item/migrations/0001_initial.py +21 -22
  10. edc_action_item/migrations/0006_auto_20180707_1659.py +4 -4
  11. edc_action_item/migrations/0008_auto_20180809_0303.py +4 -4
  12. edc_action_item/migrations/0015_auto_20190114_0250.py +4 -4
  13. edc_action_item/migrations/0017_auto_20190305_0123.py +11 -30
  14. edc_action_item/migrations/0030_edcpermissions.py +3 -2
  15. edc_action_item/migrations/0039_alter_actionitem_auto_created_comment_and_more.py +398 -0
  16. edc_action_item/migrations/0040_alter_actionitem_report_datetime_and_more.py +34 -0
  17. edc_action_item/models/action_item.py +9 -4
  18. edc_action_item/models/action_model_mixin.py +5 -6
  19. edc_action_item/models/reference.py +2 -2
  20. edc_action_item/models/signals.py +22 -23
  21. edc_action_item/post_migrate_signals.py +1 -1
  22. edc_action_item/send_email.py +0 -85
  23. edc_action_item/site_action_items.py +5 -9
  24. edc_action_item/utils.py +3 -3
  25. edc_adherence/migrations/0005_alter_nonadherencereasons_extra_value_and_more.py +36 -0
  26. edc_adherence/model_mixins.py +1 -1
  27. edc_adverse_event/auths.py +55 -51
  28. edc_adverse_event/migrations/0001_initial.py +5 -4
  29. edc_adverse_event/migrations/0002_auto_20190802_0059.py +3 -2
  30. edc_adverse_event/migrations/0008_auto_20220825_0451.py +3 -2
  31. edc_adverse_event/migrations/0009_auto_20220907_0157.py +3 -2
  32. edc_adverse_event/migrations/0016_alter_aeactionclassification_device_created_and_more.py +285 -0
  33. edc_adverse_event/model_mixins/ae_followup/ae_followup_fields_model_mixin.py +2 -2
  34. edc_adverse_event/model_mixins/ae_initial/ae_initial_fields_model_mixin.py +6 -5
  35. edc_adverse_event/model_mixins/ae_special_interest/aesi_fields_model_mixin.py +2 -2
  36. edc_adverse_event/model_mixins/ae_susar/ae_susar_fields_model_mixin.py +2 -2
  37. edc_adverse_event/model_mixins/ae_tmg/ae_tmg_fields_model_mixin.py +15 -11
  38. edc_adverse_event/model_mixins/ae_tmg/ae_tmg_methods_model_mixin.py +2 -4
  39. edc_adverse_event/model_mixins/death_report/death_report_model_mixin.py +5 -4
  40. edc_adverse_event/model_mixins/death_report/death_report_tmg_model_mixin.py +6 -3
  41. edc_adverse_event/model_mixins/death_report/simple_death_report_model_mixin.py +2 -2
  42. edc_adverse_event/model_mixins/hospitaization/hospitalization_model_mixin.py +4 -3
  43. edc_adverse_event/modeladmin_mixins/death_report_admin_mixin.py +3 -3
  44. edc_adverse_event/models/signals.py +7 -7
  45. edc_adverse_event/templatetags/edc_adverse_event_extras.py +5 -4
  46. edc_adverse_event/view_mixins/ae/ae_listboard_view_mixin.py +3 -5
  47. edc_adverse_event/view_mixins/ae/death_report_listboard_view_mixin.py +6 -8
  48. edc_adverse_event/view_mixins/tmg/tmg_ae_listboard_view_mixin.py +2 -2
  49. edc_adverse_event/views/tmg/summary_listboard_view.py +3 -2
  50. edc_appointment/admin/appointment_admin.py +2 -2
  51. edc_appointment/admin/list_filters.py +2 -2
  52. edc_appointment/auths.py +14 -10
  53. edc_appointment/creators/appointment_creator.py +1 -1
  54. edc_appointment/creators/appointments_creator.py +1 -1
  55. edc_appointment/form_validators/appointment_form_validator.py +108 -82
  56. edc_appointment/migrations/0003_auto_20161127_2226.py +5 -6
  57. edc_appointment/migrations/0006_auto_20170106_2118.py +5 -5
  58. edc_appointment/migrations/0018_auto_20190305_0123.py +5 -12
  59. edc_appointment/migrations/0050_alter_appointment_appt_type_and_more.py +220 -0
  60. edc_appointment/model_mixins/appointment_fields_model_mixin.py +1 -2
  61. edc_appointment/model_mixins/appointment_methods_model_mixin.py +2 -3
  62. edc_appointment/model_mixins/appointment_model_mixin.py +31 -28
  63. edc_appointment/model_mixins/window_period_model_mixin.py +6 -7
  64. edc_appointment/models/appointment.py +1 -1
  65. edc_appointment/models/signals.py +44 -35
  66. edc_appointment/utils.py +19 -24
  67. edc_appointment/view_utils/appointment_button.py +2 -2
  68. edc_auth/admin/user_admin.py +1 -1
  69. edc_auth/auth_objects/__init__.py +2 -20
  70. edc_auth/auth_objects/default_groups.py +13 -11
  71. edc_auth/auth_objects/default_roles.py +26 -24
  72. edc_auth/auth_updater/auth_updater.py +13 -2
  73. edc_auth/auth_updater/group_updater.py +12 -10
  74. edc_auth/auth_updater/role_updater.py +2 -2
  75. edc_auth/constants.py +10 -0
  76. edc_auth/import_users.py +3 -3
  77. edc_auth/migrations/0001_squashed_0033_alter_userprofile_is_multisite_viewer.py +5 -5
  78. edc_auth/migrations/0012_auto_20191026_0034.py +3 -2
  79. edc_auth/migrations/0013_auto_20191026_0055.py +3 -2
  80. edc_auth/migrations/0025_permissions.py +3 -2
  81. edc_auth/migrations/0035_alter_edcpermissions_device_created_and_more.py +85 -0
  82. edc_auth/models/user_profile.py +14 -11
  83. edc_auth/post_migrate_signals.py +1 -1
  84. edc_auth/site_auths.py +80 -67
  85. edc_consent/actions.py +4 -5
  86. edc_consent/auths.py +18 -12
  87. edc_consent/migrations/0001_initial.py +3 -2
  88. edc_consent/migrations/0006_alter_edcpermissions_device_created_and_more.py +49 -0
  89. edc_consent/model_mixins/consent_extension_model_mixin.py +4 -5
  90. edc_consent/model_mixins/requires_consent_fields_model_mixin.py +2 -2
  91. edc_consent/utils.py +1 -1
  92. edc_constants/constants.py +1 -0
  93. edc_crf/auths.py +5 -0
  94. edc_crf/migrations/0001_initial.py +3 -2
  95. edc_crf/migrations/0009_alter_crfstatus_device_created_and_more.py +54 -0
  96. edc_dashboard/auths.py +10 -6
  97. edc_dashboard/migrations/0001_initial.py +3 -2
  98. edc_dashboard/migrations/0006_alter_edcpermissions_device_created_and_more.py +49 -0
  99. edc_dashboard/templatetags/edc_dashboard_extras.py +3 -2
  100. edc_dashboard/url_config.py +92 -83
  101. edc_dashboard/url_names.py +4 -4
  102. edc_dashboard/view_mixins/url_request_context_mixin.py +6 -5
  103. edc_data_manager/action_items.py +4 -6
  104. edc_data_manager/admin/actions.py +5 -5
  105. edc_data_manager/admin/data_query_admin.py +12 -11
  106. edc_data_manager/auths.py +37 -34
  107. edc_data_manager/handlers/handlers.py +6 -7
  108. edc_data_manager/migrations/0001_initial.py +19 -19
  109. edc_data_manager/migrations/0025_edcpermissions.py +3 -2
  110. edc_data_manager/migrations/0040_alter_datadictionary_device_created_and_more.py +327 -0
  111. edc_data_manager/migrations/0041_alter_dataquery_dm_user_and_more.py +164 -0
  112. edc_data_manager/models/data_query.py +5 -5
  113. edc_data_manager/models/model_mixins.py +8 -8
  114. edc_data_manager/rule/query_rule_wrapper.py +7 -7
  115. edc_data_manager/rule/rule_runner.py +4 -3
  116. edc_document_status/model_mixins.py +1 -1
  117. edc_egfr/egfr.py +11 -7
  118. edc_egfr/model_mixins/egfr_model_mixin.py +3 -7
  119. edc_export/admin/data_request_admin.py +2 -2
  120. edc_export/archive_exporter.py +7 -5
  121. edc_export/auths.py +32 -28
  122. edc_export/files_archiver.py +3 -2
  123. edc_export/migrations/0001_initial.py +26 -26
  124. edc_export/migrations/0004_auto_20190305_0123.py +25 -72
  125. edc_export/migrations/0013_edcpermissions.py +3 -2
  126. edc_export/migrations/0022_alter_datarequest_description_and_more.py +611 -0
  127. edc_export/migrations/0023_alter_datarequesthistory_archive_filename_and_more.py +29 -0
  128. edc_export/model_exporter/file_history_updater.py +10 -10
  129. edc_export/model_exporter/model_exporter.py +17 -15
  130. edc_export/model_exporter/object_history_helpers.py +2 -2
  131. edc_export/models/data_request_history.py +4 -4
  132. edc_export/utils.py +10 -15
  133. edc_facility/auths.py +8 -3
  134. edc_facility/facility.py +16 -22
  135. edc_facility/import_holidays.py +13 -13
  136. edc_facility/migrations/0005_healthfacility_healthfacilitytypes_and_more.py +8 -7
  137. edc_facility/migrations/0016_alter_healthfacility_device_created_and_more.py +139 -0
  138. edc_facility/migrations/0017_alter_healthfacility_gps_and_more.py +54 -0
  139. edc_facility/model_mixins.py +5 -5
  140. edc_form_label/custom_label_condition.py +11 -8
  141. edc_form_label/form_label.py +1 -1
  142. edc_form_runners/auths.py +11 -6
  143. edc_form_runners/form_runner.py +3 -5
  144. edc_form_runners/migrations/0001_initial.py +3 -2
  145. edc_form_runners/migrations/0005_alter_issue_device_created_and_more.py +49 -0
  146. edc_form_validators/applicable_field_validator.py +7 -6
  147. edc_form_validators/base_form_validator.py +8 -9
  148. edc_form_validators/other_specify_field_validator.py +2 -8
  149. edc_form_validators/required_field_validator.py +19 -16
  150. edc_identifier/migrations/0001_squashed_0018_auto_20180128_1054.py +3 -3
  151. edc_identifier/migrations/0002_auto_20190305_0123.py +3 -6
  152. edc_identifier/migrations/0006_auto_20161127_2226.py +15 -15
  153. edc_identifier/migrations/0007_auto_20161204_2227.py +3 -3
  154. edc_identifier/migrations/0009_auto_20161221_2323.py +3 -5
  155. edc_identifier/migrations/0010_auto_20170112_0602.py +17 -17
  156. edc_identifier/migrations/0011_alter_identifiermodel_device_created_and_more.py +79 -0
  157. edc_identifier/model_mixins.py +1 -1
  158. edc_identifier/models.py +9 -9
  159. edc_identifier/research_identifier.py +11 -10
  160. edc_identifier/simple_identifier.py +9 -5
  161. edc_identifier/subject_identifier.py +3 -2
  162. edc_lab/auths.py +26 -23
  163. edc_lab/lab/aliquot_creator.py +5 -8
  164. edc_lab/lab/primary_aliquot.py +14 -5
  165. edc_lab/migrations/0001_initial.py +29 -29
  166. edc_lab/migrations/0008_auto_20170921_0719.py +3 -3
  167. edc_lab/migrations/0010_auto_20171127_1541.py +15 -15
  168. edc_lab/migrations/0012_auto_20180114_1438.py +3 -3
  169. edc_lab/migrations/0019_auto_20190305_0123.py +43 -127
  170. edc_lab/migrations/0036_alter_aliquot_comment_alter_aliquot_device_created_and_more.py +1139 -0
  171. edc_lab/migrations/0037_alter_historicalorder_order_datetime_and_more.py +31 -0
  172. edc_lab/model_mixins/aliquot/aliquot_identifier_model_mixin.py +2 -2
  173. edc_lab/model_mixins/aliquot/aliquot_model_mixin.py +2 -2
  174. edc_lab/model_mixins/panel_model_mixin.py +18 -7
  175. edc_lab/model_mixins/requisition/crf_with_requisition_model_mixin.py +2 -4
  176. edc_lab/model_mixins/requisition/requisition_model_mixin.py +13 -16
  177. edc_lab/model_mixins/requisition/requisition_verify_model_mixin.py +1 -1
  178. edc_lab/model_mixins/result/result_item_model_mixin.py +4 -4
  179. edc_lab/model_mixins/shipping/manifest_model_mixin.py +4 -5
  180. edc_lab/model_mixins/shipping/verify_model_mixin.py +4 -6
  181. edc_lab/models/aliquot.py +2 -2
  182. edc_lab/models/box.py +1 -1
  183. edc_lab/models/box_item.py +6 -7
  184. edc_lab/models/manifest/manifest.py +3 -3
  185. edc_lab/models/manifest/manifest_item.py +7 -7
  186. edc_lab/models/manifest/shipper.py +3 -4
  187. edc_lab/models/order.py +6 -4
  188. edc_lab/models/panel.py +4 -4
  189. edc_lab/models/result.py +2 -2
  190. edc_lab/models/result_item.py +2 -2
  191. edc_lab_dashboard/auths.py +16 -11
  192. edc_lab_dashboard/migrations/0001_initial.py +3 -2
  193. edc_lab_dashboard/migrations/0005_alter_edcpermissions_device_created_and_more.py +49 -0
  194. edc_lab_dashboard/views/action_views/receive_view.py +2 -2
  195. edc_lab_dashboard/views/action_views/verify_box_item_view.py +2 -2
  196. edc_lab_results/calculate_missing.py +8 -8
  197. edc_lab_results/form_validator_mixins/blood_results_form_validator_mixin.py +2 -2
  198. edc_lab_results/get_summary.py +26 -25
  199. edc_lab_results/model_mixins/blood_result_model_mixin.py +9 -7
  200. edc_lab_results/model_mixins/fbg_model_mixin.py +3 -3
  201. edc_lab_results/model_mixins/glucose_model_mixin.py +3 -3
  202. edc_lab_results/model_mixins/hba1c_model_mixin.py +3 -3
  203. edc_label/auths.py +6 -1
  204. edc_label/label_template.py +8 -8
  205. edc_label/migrations/0001_initial.py +3 -2
  206. edc_label/migrations/0007_alter_zpllabeltemplates_device_created_and_more.py +49 -0
  207. edc_list_data/list_model_maker.py +2 -2
  208. edc_list_data/load_list_data.py +11 -14
  209. edc_list_data/load_model_data.py +3 -3
  210. edc_list_data/model_mixins.py +12 -4
  211. edc_list_data/post_migrate_signals.py +1 -1
  212. edc_list_data/preload_data.py +4 -4
  213. edc_list_data/row.py +1 -1
  214. edc_list_data/site_list_data.py +6 -5
  215. edc_listboard/migrations/0001_initial.py +3 -2
  216. edc_listboard/migrations/0007_alter_listboard_device_created_and_more.py +49 -0
  217. edc_locator/auths.py +18 -13
  218. edc_locator/migrations/0001_initial.py +7 -7
  219. edc_locator/migrations/0018_auto_20190305_0123.py +5 -12
  220. edc_locator/migrations/0040_alter_historicalsubjectlocator_action_identifier_and_more.py +187 -0
  221. edc_locator/migrations/0041_alter_historicalsubjectlocator_report_datetime_and_more.py +27 -0
  222. edc_locator/model_mixins/locator_model_mixin.py +2 -2
  223. edc_locator/model_mixins/subject_contact_fields_mixin.py +1 -1
  224. edc_locator/modeladmin_mixins.py +5 -4
  225. edc_ltfu/model_mixins.py +7 -5
  226. edc_metadata/auths.py +11 -7
  227. edc_metadata/metadata/metadata.py +1 -1
  228. edc_metadata/metadata_rules/crf/crf_rule.py +1 -1
  229. edc_metadata/metadata_rules/decorators.py +1 -1
  230. edc_metadata/metadata_rules/metadata_rule_evaluator.py +5 -3
  231. edc_metadata/metadata_rules/rule.py +2 -3
  232. edc_metadata/metadata_rules/rule_evaluator.py +1 -1
  233. edc_metadata/migrations/0002_auto_20161127_2226.py +5 -5
  234. edc_metadata/migrations/0005_auto_20170112_0602.py +5 -5
  235. edc_metadata/migrations/0011_auto_20190305_0123.py +5 -12
  236. edc_metadata/migrations/0031_alter_crfmetadata_device_created_and_more.py +120 -0
  237. edc_metadata/model_mixins/updates/updates_crf_metadata_model_mixin.py +7 -4
  238. edc_metadata/model_mixins/updates/updates_requisition_metadata_model_mixin.py +5 -2
  239. edc_metadata/models/crf_metadata.py +5 -5
  240. edc_metadata/models/crf_metadata_model_mixin.py +4 -5
  241. edc_metadata/models/requisition_metadata.py +6 -6
  242. edc_metadata/models/signals.py +10 -11
  243. edc_metadata/views/refresh_metadata_actions_view.py +3 -3
  244. edc_model/models/address_mixin.py +6 -6
  245. edc_model/models/fields/initials_field.py +2 -1
  246. edc_model/models/historical_records.py +2 -9
  247. edc_model/models/url_model_mixin.py +2 -2
  248. edc_model/validators/date.py +7 -8
  249. edc_model_admin/list_filters/future_date_list_filter.py +3 -3
  250. edc_model_admin/list_filters/past_date_list_filter.py +3 -3
  251. edc_model_admin/mixins/model_admin_protect_pii_mixin.py +4 -5
  252. edc_model_fields/fields/other_charfield.py +2 -2
  253. edc_navbar/auths.py +18 -13
  254. edc_navbar/migrations/0004_auto_20220825_0451.py +3 -2
  255. edc_navbar/migrations/0009_alter_edcpermissions_device_created_and_more.py +49 -0
  256. edc_notification/auths.py +9 -4
  257. edc_notification/migrations/0001_initial.py +3 -3
  258. edc_notification/migrations/0004_auto_20190305_0123.py +3 -6
  259. edc_notification/migrations/0011_alter_notification_device_created_and_more.py +59 -0
  260. edc_notification/models/notification.py +1 -1
  261. edc_notification/notification/graded_event_notification.py +2 -2
  262. edc_notification/notification/model_notification.py +3 -30
  263. edc_notification/notification/new_model_notification.py +1 -1
  264. edc_notification/notification/notification.py +12 -12
  265. edc_notification/notification/updated_model_notification.py +2 -2
  266. edc_offstudy/auths.py +12 -7
  267. edc_offstudy/migrations/0001_initial.py +4 -4
  268. edc_offstudy/migrations/0002_auto_20180921_0434.py +4 -4
  269. edc_offstudy/migrations/0005_auto_20190305_0123.py +5 -12
  270. edc_offstudy/migrations/0023_alter_historicalsubjectoffstudy_action_identifier_and_more.py +188 -0
  271. edc_offstudy/migrations/0024_alter_historicalsubjectoffstudy_offstudy_datetime_and_more.py +43 -0
  272. edc_offstudy/model_mixins/offstudy_model_mixin.py +3 -2
  273. edc_pdutils/df_exporters/csv_exporter.py +33 -37
  274. edc_pdutils/df_exporters/csv_model_exporter.py +7 -3
  275. edc_pdutils/migrations/0001_initial.py +8 -8
  276. edc_pharmacy/admin/prescription/rx_refill_admin.py +4 -3
  277. edc_pharmacy/admin/reports/stock_availability_admin.py +5 -6
  278. edc_pharmacy/auths.py +19 -15
  279. edc_pharmacy/migrations/0001_initial.py +64 -63
  280. edc_pharmacy/migrations/0015_auto_20220913_2139.py +26 -26
  281. edc_pharmacy/migrations/0024_allocation_assignment_containerunits_dispense_and_more.py +81 -86
  282. edc_pharmacy/migrations/0037_remove_historicalstock_confirmed_at_site_by_and_more.py +5 -5
  283. edc_pharmacy/migrations/0039_remove_dispense_registered_subject_and_more.py +7 -8
  284. edc_pharmacy/migrations/0049_remove_stocktransferconfirmation_stock_and_more.py +12 -12
  285. edc_pharmacy/migrations/0050_remove_stocktransferconfirmation2_location_and_more.py +5 -5
  286. edc_pharmacy/migrations/0051_alter_historicalstocktransferconfirmationitem_options_and_more.py +3 -4
  287. edc_pharmacy/migrations/0053_alter_location_managers_alter_historicalstock_lot_and_more.py +3 -3
  288. edc_pharmacy/migrations/0057_scanduplicates.py +3 -3
  289. edc_pharmacy/migrations/0060_alter_container_max_per_subject_and_more.py +13 -15
  290. edc_pharmacy/migrations/0068_stockout.py +2 -3
  291. edc_pharmacy/migrations/0076_historicalstockadjustment_stockadjustment.py +5 -5
  292. edc_pharmacy/migrations/0077_historicalstockadjustment_adjustment_datetime_and_more.py +3 -4
  293. edc_pharmacy/migrations/0081_historicalconfirmation_confirmation.py +8 -8
  294. edc_pharmacy/migrations/0084_confirmationatsiteitem_and_more.py +0 -2
  295. edc_pharmacy/migrations/0089_alter_allocation_allocated_by_and_more.py +3284 -0
  296. edc_pharmacy/migrations/0090_alter_allocation_allocation_datetime_and_more.py +227 -0
  297. edc_pharmacy/model_mixins/study_medication_refill_model_mixin.py +2 -2
  298. edc_pharmacy/models/medication/formulation.py +5 -7
  299. edc_pharmacy/models/medication/medication.py +3 -3
  300. edc_pharmacy/models/model_mixins.py +10 -11
  301. edc_pharmacy/models/prescription/rx.py +13 -12
  302. edc_pharmacy/models/prescription/rx_refill.py +0 -1
  303. edc_pharmacy/models/stock/allocation.py +3 -3
  304. edc_pharmacy/models/stock/confirmation.py +3 -3
  305. edc_pharmacy/models/stock/confirmation_at_site.py +3 -2
  306. edc_pharmacy/models/stock/confirmation_at_site_item.py +3 -4
  307. edc_pharmacy/models/stock/dispense.py +5 -6
  308. edc_pharmacy/models/stock/dispense_item.py +2 -2
  309. edc_pharmacy/models/stock/location.py +3 -4
  310. edc_pharmacy/models/stock/lot.py +6 -7
  311. edc_pharmacy/models/stock/order.py +1 -1
  312. edc_pharmacy/models/stock/receive.py +3 -3
  313. edc_pharmacy/models/stock/receive_item.py +4 -4
  314. edc_pharmacy/models/stock/repack_request.py +2 -2
  315. edc_pharmacy/models/stock/stock.py +12 -18
  316. edc_pharmacy/models/stock/stock_adjustment.py +4 -4
  317. edc_pharmacy/models/stock/stock_request.py +2 -2
  318. edc_pharmacy/models/stock/stock_request_item.py +2 -2
  319. edc_pharmacy/models/stock/stock_transfer.py +3 -3
  320. edc_pharmacy/models/stock/stock_transfer_item.py +2 -2
  321. edc_pharmacy/models/stock/storage_bin.py +3 -4
  322. edc_pharmacy/models/stock/storage_bin_item.py +2 -2
  323. edc_pharmacy/models/stock/supplier.py +3 -4
  324. edc_pharmacy/models/storage/box.py +2 -2
  325. edc_pharmacy/models/storage/items/container_model_mixin.py +3 -4
  326. edc_pharmacy/models/storage/items/pill_bottle_model_mixin.py +2 -2
  327. edc_pharmacy/models/storage/items/subject_pill_bottle.py +1 -1
  328. edc_pharmacy/models/storage/room.py +2 -2
  329. edc_pharmacy/models/storage/shelf.py +2 -2
  330. edc_pharmacy/models/storage/utils.py +1 -1
  331. edc_pharmacy/prescribe/create_prescription.py +3 -3
  332. edc_pharmacy/utils/allocate_stock.py +2 -3
  333. edc_pharmacy/utils/confirm_stock.py +3 -4
  334. edc_pharmacy/utils/confirm_stock_at_site.py +4 -5
  335. edc_pharmacy/utils/dispense.py +3 -4
  336. edc_pharmacy/utils/process_repack_request.py +4 -5
  337. edc_pharmacy/utils/stock_request/bulk_create_stock_request_items.py +2 -3
  338. edc_pharmacy/utils/transfer_stock.py +2 -3
  339. edc_pharmacy/views/add_to_storage_bin_view.py +2 -2
  340. edc_pharmacy/views/allocate_to_subject_view.py +2 -2
  341. edc_pharmacy/views/confirmation_at_site_view.py +6 -9
  342. edc_pharmacy/views/dispense_view.py +2 -2
  343. edc_pharmacy/views/move_to_storage_bin_view.py +2 -3
  344. edc_pharmacy/views/print_labels_view.py +2 -2
  345. edc_prn/admin_site.py +5 -0
  346. edc_prn/prn.py +10 -11
  347. edc_prn/urls.py +11 -0
  348. edc_protocol/research_protocol_config.py +2 -3
  349. edc_protocol_incident/action_items.py +4 -4
  350. edc_protocol_incident/auths.py +27 -20
  351. edc_protocol_incident/migrations/0001_initial.py +7 -7
  352. edc_protocol_incident/migrations/0001_squashed_0015_auto_20220927_0401.py +13 -13
  353. edc_protocol_incident/migrations/0005_protocolincident_historicalprotocolincident_and_more.py +7 -7
  354. edc_protocol_incident/migrations/0024_alter_actionsrequired_extra_value_and_more.py +625 -0
  355. edc_protocol_incident/migrations/0025_alter_historicalprotocoldeviationviolation_report_datetime_and_more.py +42 -0
  356. edc_protocol_incident/model_mixins/protocol_deviation_violation_model_mixin.py +18 -11
  357. edc_protocol_incident/model_mixins/protocol_incident_model_mixin.py +26 -11
  358. edc_pylabels/actions.py +3 -5
  359. edc_pylabels/auths.py +6 -1
  360. edc_pylabels/migrations/0002_alter_label_options_label_created_and_more.py +3 -7
  361. edc_pylabels/migrations/0005_labelconfiguration_delete_label_and_more.py +3 -3
  362. edc_pylabels/migrations/0013_alter_labelconfiguration_device_created_and_more.py +49 -0
  363. edc_qareports/auths.py +11 -7
  364. edc_qareports/migrations/0001_initial.py +4 -5
  365. edc_qareports/migrations/0005_edcpermissions.py +3 -3
  366. edc_qareports/migrations/0006_qareportlog.py +2 -3
  367. edc_qareports/migrations/0019_alter_edcpermissions_device_created_and_more.py +102 -0
  368. edc_qareports/migrations/0020_alter_note_report_datetime_and_more.py +24 -0
  369. edc_qareports/model_mixins/note_model_mixin.py +7 -4
  370. edc_qareports/model_mixins/on_study_missing_values_model_mixin.py +4 -4
  371. edc_qareports/model_mixins/qa_report_model_mixin.py +2 -3
  372. edc_qareports/models/note.py +4 -4
  373. edc_qareports/models/qa_reports_log.py +2 -3
  374. edc_randomization/admin.py +30 -24
  375. edc_randomization/auths.py +12 -7
  376. edc_randomization/decorators.py +1 -1
  377. edc_randomization/migrations/0001_initial.py +3 -2
  378. edc_randomization/migrations/0002_historicalrandomizationlist.py +3 -2
  379. edc_randomization/migrations/0009_edcpermissions.py +3 -2
  380. edc_randomization/migrations/0014_alter_edcpermissions_device_created_and_more.py +141 -0
  381. edc_randomization/model_mixins.py +9 -9
  382. edc_randomization/randomizer.py +22 -20
  383. edc_randomization/utils.py +19 -18
  384. edc_refusal/auths.py +7 -2
  385. edc_refusal/migrations/0001_initial.py +4 -4
  386. edc_refusal/migrations/0002_historicalsubjectrefusal.py +4 -4
  387. edc_refusal/migrations/0012_alter_historicalsubjectrefusal_comment_and_more.py +122 -0
  388. edc_refusal/migrations/0013_alter_historicalsubjectrefusal_report_datetime_and_more.py +28 -0
  389. edc_refusal/model_mixins.py +4 -4
  390. edc_registration/auths.py +28 -23
  391. edc_registration/migrations/0002_auto_20161127_2226.py +3 -4
  392. edc_registration/migrations/0005_auto_20170111_1809.py +4 -2
  393. edc_registration/migrations/0016_historicalregisteredsubject.py +3 -2
  394. edc_registration/migrations/0017_auto_20190305_0123.py +5 -12
  395. edc_registration/migrations/0033_alter_historicalregisteredsubject_additional_key_and_more.py +302 -0
  396. edc_registration/model_mixins/updates_or_creates_registered_subject_model_mixin.py +15 -7
  397. edc_registration/models/registered_subject.py +28 -27
  398. edc_reportable/age_evaluator.py +4 -2
  399. edc_reportable/formula.py +5 -5
  400. edc_reportable/migrations/0001_initial.py +7 -7
  401. edc_reportable/migrations/0003_referencerangecollection_grade1_and_more.py +3 -3
  402. edc_reportable/migrations/0004_alter_referencerangecollection_grade3_and_more.py +5 -5
  403. edc_reportable/migrations/0006_alter_gradingdata_revision_and_more.py +5 -6
  404. edc_reportable/migrations/0007_alter_gradingdata_age_phrase_and_more.py +509 -0
  405. edc_reportable/models/normal_data.py +4 -5
  406. edc_reportable/models/reference_model_mixins.py +10 -11
  407. edc_reportable/models/reference_range_collection.py +12 -13
  408. edc_reportable/post_migrate_signals.py +1 -1
  409. edc_reportable/utils/convert_units.py +11 -45
  410. edc_reportable/utils/get_normal_data_or_raise.py +2 -2
  411. edc_reportable/utils/get_reference_range_collection.py +2 -3
  412. edc_reportable/utils/load_data.py +4 -4
  413. edc_reportable/utils/update_grading_data.py +5 -5
  414. edc_review_dashboard/auths.py +23 -18
  415. edc_review_dashboard/migrations/0001_initial.py +3 -2
  416. edc_review_dashboard/migrations/0006_alter_edcpermissions_device_created_and_more.py +49 -0
  417. edc_screening/age_evaluator.py +6 -6
  418. edc_screening/auths.py +35 -30
  419. edc_screening/eligibility.py +1 -1
  420. edc_screening/gender_evaluator.py +1 -1
  421. edc_screening/migrations/0001_initial.py +3 -2
  422. edc_screening/migrations/0005_alter_edcpermissions_device_created_and_more.py +49 -0
  423. edc_screening/model_mixins/eligibility_model_mixin.py +3 -6
  424. edc_screening/model_mixins/screening_fields_model_mixin.py +6 -8
  425. edc_screening/model_mixins/screening_methods_model_mixin.py +1 -1
  426. edc_screening/screening_eligibility.py +2 -4
  427. edc_screening/utils.py +9 -9
  428. edc_search/generate_slug.py +26 -0
  429. edc_search/model_mixins.py +10 -22
  430. edc_sites/auths.py +8 -3
  431. edc_sites/migrations/0007_edcpermissions.py +3 -2
  432. edc_sites/migrations/0010_alter_edcpermissions_device_created_and_more.py +69 -0
  433. edc_sites/model_mixins/site_model_mixin.py +2 -2
  434. edc_sites/site.py +5 -5
  435. edc_sites/system_checks.py +1 -1
  436. edc_subject_dashboard/auths.py +27 -22
  437. edc_subject_dashboard/migrations/0001_initial.py +3 -2
  438. edc_subject_dashboard/migrations/0005_alter_edcpermissions_device_created_and_more.py +49 -0
  439. edc_subject_dashboard/requisition_report.py +6 -4
  440. edc_subject_dashboard/requisition_verifier.py +6 -6
  441. edc_subject_dashboard/templatetags/edc_subject_dashboard_extras.py +2 -2
  442. edc_subject_dashboard/view_mixins/subject_visit_view_mixin.py +7 -8
  443. edc_subject_dashboard/view_utils/subject_consent_listboard_button.py +3 -2
  444. edc_subject_dashboard/view_utils/timepoint_status_button.py +2 -2
  445. edc_timepoint/apps.py +0 -21
  446. edc_timepoint/model_mixins.py +22 -20
  447. edc_transfer/model_mixins.py +4 -4
  448. edc_transfer/modeladmin_mixins.py +1 -1
  449. edc_unblinding/auths.py +9 -4
  450. edc_unblinding/migrations/0001_initial.py +13 -13
  451. edc_unblinding/migrations/0014_alter_historicalunblindingrequest_action_identifier_and_more.py +291 -0
  452. edc_unblinding/migrations/0015_alter_historicalunblindingrequest_report_datetime_and_more.py +45 -0
  453. edc_unblinding/models/unblinding_request.py +2 -2
  454. edc_unblinding/models/unblinding_review.py +3 -3
  455. edc_utils/__init__.py +3 -1
  456. edc_utils/age.py +10 -16
  457. edc_utils/show_urls.py +29 -2
  458. edc_visit_schedule/auths.py +6 -1
  459. edc_visit_schedule/migrations/0001_initial.py +3 -3
  460. edc_visit_schedule/migrations/0002_auto_20190305_0123.py +3 -6
  461. edc_visit_schedule/migrations/0003_historicalvisitschedule_visitschedule.py +5 -4
  462. edc_visit_schedule/migrations/0015_historicalonschedule_offschedule_onschedule.py +10 -10
  463. edc_visit_schedule/migrations/0019_alter_historicalonschedule_device_created_and_more.py +229 -0
  464. edc_visit_schedule/migrations/0020_alter_historicalonschedule_onschedule_datetime_and_more.py +65 -0
  465. edc_visit_schedule/model_mixins/off_schedule_model_mixin.py +5 -4
  466. edc_visit_schedule/model_mixins/on_schedule_model_mixin.py +5 -4
  467. edc_visit_schedule/model_mixins/visit_schedule/visit_code_fields_model_mixin.py +1 -1
  468. edc_visit_schedule/models/subject_schedule_history.py +6 -6
  469. edc_visit_schedule/schedule/visit_collection.py +1 -1
  470. edc_visit_schedule/site_visit_schedules.py +2 -2
  471. edc_visit_schedule/subject_schedule.py +5 -4
  472. edc_visit_schedule/view_mixins.py +2 -3
  473. edc_visit_schedule/visit/visit.py +3 -2
  474. edc_visit_tracking/migrations/0004_subjectvisit_subjectvisitmissedreasons_extra_value_and_more.py +13 -13
  475. edc_visit_tracking/migrations/0009_alter_historicalsubjectvisit_comments_and_more.py +450 -0
  476. edc_visit_tracking/migrations/0010_alter_historicalsubjectvisit_report_datetime_and_more.py +68 -0
  477. edc_visit_tracking/model_mixins/base/visit_methods_model_mixin.py +3 -3
  478. edc_visit_tracking/model_mixins/crfs/visit_tracking_crf_model_mixin.py +2 -2
  479. edc_visit_tracking/model_mixins/requisitions/visit_tracking_requisition_model_mixin.py +2 -2
  480. edc_visit_tracking/model_mixins/subject_visit_missed_model_mixin.py +2 -2
  481. edc_visit_tracking/model_mixins/visit_model_mixin/caretaker_fields_mixin.py +2 -3
  482. edc_visit_tracking/model_mixins/visit_model_mixin/previous_visit_model_mixin.py +1 -1
  483. edc_visit_tracking/model_mixins/visit_model_mixin/visit_model_fields_mixin.py +8 -11
  484. edc_visit_tracking/model_mixins/visit_model_mixin/visit_model_mixin.py +1 -1
  485. edc_visit_tracking/models/signals.py +3 -3
  486. edc_visit_tracking/models/subject_visit.py +1 -1
  487. edc_vitals/calculators/bmi.py +7 -5
  488. edc_vitals/utils.py +1 -1
  489. edc_form_label/models.py +0 -0
  490. edc_search/constants.py +0 -1
  491. edc_search/models.py +0 -0
  492. edc_search/search_slug.py +0 -50
  493. edc_search/updater.py +0 -30
  494. edc_search/wsgi.py +0 -7
  495. {clinicedc-2.0.6.dist-info → clinicedc-2.0.8.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,54 @@
1
+ # Generated by Django 5.2.6 on 2025-09-17 16:53
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ("edc_crf", "0008_alter_crfstatus_revision"),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterField(
14
+ model_name="crfstatus",
15
+ name="device_created",
16
+ field=models.CharField(
17
+ blank=True, default="", max_length=10, verbose_name="Device created"
18
+ ),
19
+ ),
20
+ migrations.AlterField(
21
+ model_name="crfstatus",
22
+ name="device_modified",
23
+ field=models.CharField(
24
+ blank=True, default="", max_length=10, verbose_name="Device modified"
25
+ ),
26
+ ),
27
+ migrations.AlterField(
28
+ model_name="crfstatus",
29
+ name="locale_created",
30
+ field=models.CharField(
31
+ blank=True,
32
+ default="",
33
+ help_text="Auto-updated by Modeladmin",
34
+ max_length=10,
35
+ verbose_name="Locale created",
36
+ ),
37
+ ),
38
+ migrations.AlterField(
39
+ model_name="crfstatus",
40
+ name="locale_modified",
41
+ field=models.CharField(
42
+ blank=True,
43
+ default="",
44
+ help_text="Auto-updated by Modeladmin",
45
+ max_length=10,
46
+ verbose_name="Locale modified",
47
+ ),
48
+ ),
49
+ migrations.AlterField(
50
+ model_name="crfstatus",
51
+ name="visit_code",
52
+ field=models.CharField(default="", editable=False, max_length=25),
53
+ ),
54
+ ]
edc_dashboard/auths.py CHANGED
@@ -3,11 +3,15 @@ from edc_auth.utils import remove_default_model_permissions_from_edc_permissions
3
3
 
4
4
  from .auth_objects import dashboard_tuples
5
5
 
6
- site_auths.add_post_update_func(
7
- "edc_dashboard", remove_default_model_permissions_from_edc_permissions
8
- )
9
6
 
7
+ def update_site_auths():
8
+ site_auths.add_post_update_func(
9
+ "edc_dashboard", remove_default_model_permissions_from_edc_permissions
10
+ )
10
11
 
11
- site_auths.add_custom_permissions_tuples(
12
- model="edc_dashboard.edcpermissions", codename_tuples=dashboard_tuples
13
- )
12
+ site_auths.add_custom_permissions_tuples(
13
+ model="edc_dashboard.edcpermissions", codename_tuples=dashboard_tuples
14
+ )
15
+
16
+
17
+ update_site_auths()
@@ -7,6 +7,7 @@ import django_audit_fields.fields.uuid_auto_field
7
7
  import django_audit_fields.models.audit_model_mixin
8
8
  import django_revision.revision_field
9
9
  from django.db import migrations, models
10
+ import django.utils.timezone
10
11
 
11
12
 
12
13
  class Migration(migrations.Migration):
@@ -33,14 +34,14 @@ class Migration(migrations.Migration):
33
34
  "created",
34
35
  models.DateTimeField(
35
36
  blank=True,
36
- default=django_audit_fields.models.audit_model_mixin.utcnow,
37
+ default=django.utils.timezone.now,
37
38
  ),
38
39
  ),
39
40
  (
40
41
  "modified",
41
42
  models.DateTimeField(
42
43
  blank=True,
43
- default=django_audit_fields.models.audit_model_mixin.utcnow,
44
+ default=django.utils.timezone.now,
44
45
  ),
45
46
  ),
46
47
  (
@@ -0,0 +1,49 @@
1
+ # Generated by Django 5.2.6 on 2025-09-17 16:53
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ("edc_dashboard", "0005_alter_edcpermissions_revision"),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterField(
14
+ model_name="edcpermissions",
15
+ name="device_created",
16
+ field=models.CharField(
17
+ blank=True, default="", max_length=10, verbose_name="Device created"
18
+ ),
19
+ ),
20
+ migrations.AlterField(
21
+ model_name="edcpermissions",
22
+ name="device_modified",
23
+ field=models.CharField(
24
+ blank=True, default="", max_length=10, verbose_name="Device modified"
25
+ ),
26
+ ),
27
+ migrations.AlterField(
28
+ model_name="edcpermissions",
29
+ name="locale_created",
30
+ field=models.CharField(
31
+ blank=True,
32
+ default="",
33
+ help_text="Auto-updated by Modeladmin",
34
+ max_length=10,
35
+ verbose_name="Locale created",
36
+ ),
37
+ ),
38
+ migrations.AlterField(
39
+ model_name="edcpermissions",
40
+ name="locale_modified",
41
+ field=models.CharField(
42
+ blank=True,
43
+ default="",
44
+ help_text="Auto-updated by Modeladmin",
45
+ max_length=10,
46
+ verbose_name="Locale modified",
47
+ ),
48
+ ),
49
+ ]
@@ -5,8 +5,9 @@ from django import template
5
5
  from django.conf import settings
6
6
  from django.template.defaultfilters import stringfilter
7
7
  from django.urls.base import reverse
8
+ from django.utils import timezone
8
9
 
9
- from edc_utils import AgeValueError, age, get_utcnow
10
+ from edc_utils.age import AgeValueError, age
10
11
 
11
12
  register = template.Library()
12
13
 
@@ -39,7 +40,7 @@ class UrlMaker:
39
40
  @register.simple_tag(takes_context=True)
40
41
  def age_in_years(context, born):
41
42
  if born:
42
- reference_datetime = context.get("reference_datetime") or get_utcnow()
43
+ reference_datetime = context.get("reference_datetime") or timezone.now()
43
44
  try:
44
45
  _age_in_years = age(born, reference_datetime).years
45
46
  except AgeValueError:
@@ -20,12 +20,13 @@ if TYPE_CHECKING:
20
20
  class UrlConfig:
21
21
  def __init__(
22
22
  self,
23
- url_name: str = None,
24
- namespace: str = None,
25
- view_class: type[View | UrlRequestContextMixin] = None,
26
- label: str = None,
27
- identifier_label: str = None,
28
- identifier_pattern: str = None,
23
+ *,
24
+ url_name: str,
25
+ namespace: str,
26
+ view_class: type[View | UrlRequestContextMixin],
27
+ label: str,
28
+ identifier_label: str,
29
+ identifier_pattern: str,
29
30
  ):
30
31
  self.identifier_label = identifier_label
31
32
  self.identifier_pattern = identifier_pattern
@@ -39,102 +40,108 @@ class UrlConfig:
39
40
  @property
40
41
  def dashboard_urls(self) -> list[URLPattern]:
41
42
  """Returns url patterns."""
42
- urlpatterns = [
43
+ return [
43
44
  re_path(
44
- "%(label)s/"
45
- "(?P<%(identifier_label)s>%(identifier_pattern)s)/"
45
+ "{label}/"
46
+ "(?P<{identifier_label}>{identifier_pattern})/"
46
47
  r"(?P<visit_schedule_name>\w+)/"
47
48
  r"(?P<schedule_name>\w+)/"
48
49
  r"(?P<visit_code>\w+)/"
49
- r"(?P<unscheduled>\w+)/"
50
- % {
51
- "label": self.label,
52
- "identifier_label": self.identifier_label,
53
- "identifier_pattern": self.identifier_pattern,
54
- },
50
+ r"(?P<unscheduled>\w+)/".format(
51
+ **dict(
52
+ label=self.label,
53
+ identifier_label=self.identifier_label,
54
+ identifier_pattern=self.identifier_pattern,
55
+ )
56
+ ),
55
57
  self.view_class.as_view(),
56
58
  name=self.url_name,
57
59
  ),
58
60
  re_path(
59
- "%(label)s/"
60
- "(?P<%(identifier_label)s>%(identifier_pattern)s)/"
61
+ "{label}/"
62
+ "(?P<{identifier_label}>{identifier_pattern})/"
61
63
  r"(?P<visit_schedule_name>\w+)/"
62
64
  r"(?P<schedule_name>\w+)/"
63
- r"(?P<visit_code>\w+)/"
64
- % dict(
65
- label=self.label,
66
- identifier_label=self.identifier_label,
67
- identifier_pattern=self.identifier_pattern,
65
+ r"(?P<visit_code>\w+)/".format(
66
+ **dict(
67
+ label=self.label,
68
+ identifier_label=self.identifier_label,
69
+ identifier_pattern=self.identifier_pattern,
70
+ )
68
71
  ),
69
72
  self.view_class.as_view(),
70
73
  name=self.url_name,
71
74
  ),
72
75
  re_path(
73
- "%(label)s/"
74
- "(?P<%(identifier_label)s>%(identifier_pattern)s)/"
75
- "(?P<appointment>%(uuid_pattern)s)/"
76
+ "{label}/"
77
+ "(?P<{identifier_label}>{identifier_pattern})/"
78
+ "(?P<appointment>{uuid_pattern})/"
76
79
  r"(?P<scanning>\d)/"
77
- r"(?P<error>\d)/"
78
- % dict(
79
- label=self.label,
80
- identifier_label=self.identifier_label,
81
- identifier_pattern=self.identifier_pattern,
82
- uuid_pattern=UUID_PATTERN.pattern,
80
+ r"(?P<error>\d)/".format(
81
+ **dict(
82
+ label=self.label,
83
+ identifier_label=self.identifier_label,
84
+ identifier_pattern=self.identifier_pattern,
85
+ uuid_pattern=UUID_PATTERN.pattern,
86
+ )
83
87
  ),
84
88
  self.view_class.as_view(),
85
89
  name=self.url_name,
86
90
  ),
87
91
  re_path(
88
- "%(label)s/"
89
- "(?P<%(identifier_label)s>%(identifier_pattern)s)/"
90
- "(?P<appointment>%(uuid_pattern)s)/"
91
- r"(?P<reason>\w+)/"
92
- % dict(
93
- label=self.label,
94
- identifier_label=self.identifier_label,
95
- identifier_pattern=self.identifier_pattern,
96
- uuid_pattern=UUID_PATTERN.pattern,
92
+ "{label}/"
93
+ "(?P<{identifier_label}>{identifier_pattern})/"
94
+ "(?P<appointment>{uuid_pattern})/"
95
+ r"(?P<reason>\w+)/".format(
96
+ **dict(
97
+ label=self.label,
98
+ identifier_label=self.identifier_label,
99
+ identifier_pattern=self.identifier_pattern,
100
+ uuid_pattern=UUID_PATTERN.pattern,
101
+ )
97
102
  ),
98
103
  self.view_class.as_view(),
99
104
  name=self.url_name,
100
105
  ),
101
106
  re_path(
102
- "%(label)s/"
103
- "(?P<%(identifier_label)s>%(identifier_pattern)s)/"
104
- "(?P<appointment>%(uuid_pattern)s)/"
105
- % dict(
106
- label=self.label,
107
- identifier_label=self.identifier_label,
108
- identifier_pattern=self.identifier_pattern,
109
- uuid_pattern=UUID_PATTERN.pattern,
107
+ "{label}/"
108
+ "(?P<{identifier_label}>{identifier_pattern})/"
109
+ "(?P<appointment>{uuid_pattern})/".format(
110
+ **dict(
111
+ label=self.label,
112
+ identifier_label=self.identifier_label,
113
+ identifier_pattern=self.identifier_pattern,
114
+ uuid_pattern=UUID_PATTERN.pattern,
115
+ )
110
116
  ),
111
117
  self.view_class.as_view(),
112
118
  name=self.url_name,
113
119
  ),
114
120
  re_path(
115
- "%(label)s/"
116
- "(?P<%(identifier_label)s>%(identifier_pattern)s)/"
117
- r"(?P<schedule_name>\w+)/"
118
- % dict(
119
- label=self.label,
120
- identifier_label=self.identifier_label,
121
- identifier_pattern=self.identifier_pattern,
121
+ "{label}/"
122
+ "(?P<{identifier_label}>{identifier_pattern})/"
123
+ r"(?P<schedule_name>\w+)/".format(
124
+ **dict(
125
+ label=self.label,
126
+ identifier_label=self.identifier_label,
127
+ identifier_pattern=self.identifier_pattern,
128
+ )
122
129
  ),
123
130
  self.view_class.as_view(),
124
131
  name=self.url_name,
125
132
  ),
126
133
  re_path(
127
- "%(label)s/(?P<%(identifier_label)s>%(identifier_pattern)s)/"
128
- % dict(
129
- label=self.label,
130
- identifier_label=self.identifier_label,
131
- identifier_pattern=self.identifier_pattern,
134
+ "{label}/(?P<{identifier_label}>{identifier_pattern})/".format(
135
+ **dict(
136
+ label=self.label,
137
+ identifier_label=self.identifier_label,
138
+ identifier_pattern=self.identifier_pattern,
139
+ )
132
140
  ),
133
141
  self.view_class.as_view(),
134
142
  name=self.url_name,
135
143
  ),
136
144
  ]
137
- return urlpatterns
138
145
 
139
146
  @property
140
147
  def listboard_urls(self) -> list[URLPattern]:
@@ -142,52 +149,54 @@ class UrlConfig:
142
149
 
143
150
  configs = [(listboard_url, listboard_view_class, label), (), ...]
144
151
  """
145
- urlpatterns = [
152
+ return [
146
153
  re_path(
147
- "%(label)s/(?P<%(identifier_label)s>%(identifier_pattern)s)/"
148
- r"(?P<page>\d+)/"
149
- % dict(
150
- label=self.label,
151
- identifier_label=self.identifier_label,
152
- identifier_pattern=self.identifier_pattern,
154
+ "{label}/(?P<{identifier_label}>{identifier_pattern})/"
155
+ r"(?P<page>\d+)/".format(
156
+ **dict(
157
+ label=self.label,
158
+ identifier_label=self.identifier_label,
159
+ identifier_pattern=self.identifier_pattern,
160
+ )
153
161
  ),
154
162
  self.view_class.as_view(),
155
163
  name=self.url_name,
156
164
  ),
157
165
  re_path(
158
- "%(label)s/(?P<%(identifier_label)s>%(identifier_pattern)s)/"
159
- % dict(
160
- label=self.label,
161
- identifier_label=self.identifier_label,
162
- identifier_pattern=self.identifier_pattern,
166
+ "{label}/(?P<{identifier_label}>{identifier_pattern})/".format(
167
+ **dict(
168
+ label=self.label,
169
+ identifier_label=self.identifier_label,
170
+ identifier_pattern=self.identifier_pattern,
171
+ )
163
172
  ),
164
173
  self.view_class.as_view(),
165
174
  name=self.url_name,
166
175
  ),
167
176
  re_path(
168
- r"%(label)s/(?P<page>\d+)/" % dict(label=self.label),
177
+ r"{label}/(?P<page>\d+)/".format(**dict(label=self.label)),
169
178
  self.view_class.as_view(),
170
179
  name=self.url_name,
171
180
  ),
172
181
  re_path(
173
- r"%(label)s/" % dict(label=self.label),
182
+ r"{label}/".format(**dict(label=self.label)),
174
183
  self.view_class.as_view(),
175
184
  name=self.url_name,
176
185
  ),
177
186
  ]
178
- return urlpatterns
179
187
 
180
188
  @property
181
189
  def review_listboard_urls(self) -> list[URLPattern]:
182
190
  url_patterns = [
183
191
  re_path(
184
- "%(label)s/(?P<%(identifier_label)s>%(identifier_pattern)s)/"
185
- "(?P<appointment>%(uuid_pattern)s)/"
186
- % dict(
187
- label=self.label,
188
- identifier_label=self.identifier_label,
189
- identifier_pattern=self.identifier_pattern,
190
- uuid_pattern=UUID_PATTERN.pattern,
192
+ "{label}/(?P<{identifier_label}>{identifier_pattern})/"
193
+ "(?P<appointment>{uuid_pattern})/".format(
194
+ **dict(
195
+ label=self.label,
196
+ identifier_label=self.identifier_label,
197
+ identifier_pattern=self.identifier_pattern,
198
+ uuid_pattern=UUID_PATTERN.pattern,
199
+ )
191
200
  ),
192
201
  self.view_class.as_view(),
193
202
  name=self.url_name,
@@ -3,11 +3,11 @@ from __future__ import annotations
3
3
  from dataclasses import dataclass, field
4
4
 
5
5
 
6
- class AlreadyRegistered(Exception):
6
+ class AlreadyRegistered(Exception): # noqa: N818
7
7
  pass
8
8
 
9
9
 
10
- class InvalidDashboardUrlName(Exception):
10
+ class InvalidDashboardUrlName(Exception): # noqa: N818
11
11
  pass
12
12
 
13
13
 
@@ -16,12 +16,12 @@ class UrlNames:
16
16
  registry: dict[str, str] = field(default_factory=dict)
17
17
 
18
18
  def register(
19
- self, name: str = None, url: str = None, namespace: str | None = None
19
+ self, name: str | None = None, url: str | None = None, namespace: str | None = None
20
20
  ) -> None:
21
21
  name = name or url
22
22
  complete_url = f"{namespace}:{url}" if namespace else url
23
23
  if name in self.registry:
24
- raise AlreadyRegistered(f"Url already registered. Got {name}.")
24
+ raise AlreadyRegistered(f"Url already registered. Got {complete_url}.")
25
25
  self.registry.update({name: complete_url})
26
26
 
27
27
  def register_from_dict(self, **urldata: str) -> None:
@@ -30,10 +30,11 @@ class UrlRequestContextMixin:
30
30
  @classmethod
31
31
  def urls(
32
32
  cls,
33
- namespace: str = None,
34
- label: str = None,
35
- identifier_label: str = None,
36
- identifier_pattern: str = None,
33
+ *,
34
+ label: str,
35
+ identifier_pattern: str,
36
+ namespace: str | None = None,
37
+ identifier_label: str | None = None,
37
38
  ) -> list[URLPattern]:
38
39
  label = (
39
40
  label
@@ -62,5 +63,5 @@ class UrlRequestContextMixin:
62
63
  f"Url name not defined in url_names. "
63
64
  f"Expected one of {url_names.registry}. Got {e}. "
64
65
  f"Hint: check if dashboard middleware is loaded."
65
- )
66
+ ) from e
66
67
  return url_data
@@ -1,5 +1,6 @@
1
1
  from django.conf import settings
2
2
  from django.template.loader import render_to_string
3
+ from django.utils import timezone
3
4
 
4
5
  from edc_action_item.action import Action
5
6
  from edc_action_item.site_action_items import site_action_items
@@ -11,7 +12,6 @@ from edc_constants.constants import (
11
12
  NORMAL,
12
13
  RESOLVED,
13
14
  )
14
- from edc_utils.date import get_utcnow
15
15
 
16
16
  from .constants import CLOSED_WITH_ACTION
17
17
 
@@ -35,12 +35,10 @@ class DataQueryAction(Action):
35
35
  return not self.close_action_item_on_save()
36
36
 
37
37
  def close_action_item_on_save(self):
38
- if self.reference_obj and self.reference_obj.status in [
38
+ return self.reference_obj and self.reference_obj.status in [
39
39
  CLOSED,
40
40
  CLOSED_WITH_ACTION,
41
- ]:
42
- return True
43
- return False
41
+ ]
44
42
 
45
43
  def get_priority(self):
46
44
  return self.query_priority or self.priority
@@ -98,7 +96,7 @@ class DataQueryAction(Action):
98
96
  object=self.reference_obj,
99
97
  query_priority=query_priority,
100
98
  title=title,
101
- utcnow=get_utcnow(),
99
+ utcnow=timezone.now(),
102
100
  visit_schedule=visit_schedule,
103
101
  )
104
102
  form_and_numbers_to_string = getattr(
@@ -4,11 +4,12 @@ from django.conf import settings
4
4
  from django.contrib import admin, messages
5
5
  from django.core.exceptions import ObjectDoesNotExist
6
6
  from django.urls.base import reverse
7
+ from django.utils import timezone
7
8
  from django.utils.html import format_html
8
9
  from django.utils.safestring import mark_safe
9
10
 
10
11
  from edc_constants.constants import CLOSED, OPEN
11
- from edc_utils import formatted_datetime, get_utcnow
12
+ from edc_utils import formatted_datetime
12
13
 
13
14
  from ..models import QueryRule
14
15
  from ..rule import update_query_rules
@@ -65,14 +66,13 @@ def copy_query_rule_action(modeladmin, request, queryset):
65
66
  def update_query_rules_action(modeladmin, request, queryset):
66
67
  if not DATA_MANAGER_ENABLED:
67
68
  msg = (
68
- "Data manager features are currently disabled. "
69
- "See settings.DATA_MANAGER_ENABLED."
69
+ "Data manager features are currently disabled. See settings.DATA_MANAGER_ENABLED."
70
70
  )
71
71
  messages.add_message(request, messages.ERROR, msg)
72
72
  elif queryset:
73
73
  if settings.CELERY_ENABLED:
74
74
  update_query_rules.delay(pks=[o.pk for o in queryset])
75
- dte = get_utcnow()
75
+ dte = timezone.now()
76
76
  taskresult_url = reverse("admin:django_celery_results_taskresult_changelist")
77
77
  msg = format_html(
78
78
  "Updating data queries in the background. "
@@ -86,7 +86,7 @@ def update_query_rules_action(modeladmin, request, queryset):
86
86
  else:
87
87
  results = update_query_rules(pks=[o.pk for o in queryset])
88
88
  msg = format_html(
89
- "Done updating data queries. Created {}, " "resolved {}.",
89
+ "Done updating data queries. Created {}, resolved {}.",
90
90
  mark_safe(results.get("created")), # nosec B703, B308
91
91
  mark_safe(results.get("resolved")), # nosec B703, B308
92
92
  )
@@ -45,7 +45,7 @@ class DataQueryAdmin(SiteModelAdminMixin, ModelAdminSubjectDashboardMixin, Simpl
45
45
 
46
46
  locked_column_template_name = "edc_data_manager/columns/locked.html"
47
47
 
48
- status_column_context = {
48
+ status_column_context = { # noqa: RUF012
49
49
  "NEW": NEW,
50
50
  "OPEN": OPEN,
51
51
  "FEEDBACK": FEEDBACK,
@@ -61,13 +61,13 @@ class DataQueryAdmin(SiteModelAdminMixin, ModelAdminSubjectDashboardMixin, Simpl
61
61
 
62
62
  actions = (toggle_dm_status,)
63
63
 
64
- radio_fields = {
64
+ radio_fields = { # noqa: RUF012
65
65
  "status": admin.VERTICAL,
66
66
  "site_response_status": admin.VERTICAL,
67
67
  "query_priority": admin.VERTICAL,
68
68
  }
69
69
 
70
- autocomplete_fields = [
70
+ autocomplete_fields = (
71
71
  "sender",
72
72
  "recipients",
73
73
  "data_dictionaries",
@@ -75,7 +75,7 @@ class DataQueryAdmin(SiteModelAdminMixin, ModelAdminSubjectDashboardMixin, Simpl
75
75
  "visit_schedule",
76
76
  "registered_subject",
77
77
  "dm_user",
78
- ]
78
+ )
79
79
 
80
80
  list_display = (
81
81
  "wrapped_title",
@@ -201,11 +201,10 @@ class DataQueryAdmin(SiteModelAdminMixin, ModelAdminSubjectDashboardMixin, Simpl
201
201
  wrapped_title.short_description = "Title"
202
202
 
203
203
  def formfield_for_manytomany(self, db_field, request, **kwargs):
204
- if db_field.name == "data_dictionaries":
205
- if request.GET.get("title"):
206
- kwargs["queryset"] = DataDictionary.objects.filter(
207
- model_verbose_name=request.GET.get("title")
208
- )
204
+ if db_field.name == "data_dictionaries" and request.GET.get("title"):
205
+ kwargs["queryset"] = DataDictionary.objects.filter(
206
+ model_verbose_name=request.GET.get("title")
207
+ )
209
208
  return super().formfield_for_manytomany(db_field, request, **kwargs)
210
209
 
211
210
  def query_dates(self, obj):
@@ -332,7 +331,8 @@ class DataQueryAdmin(SiteModelAdminMixin, ModelAdminSubjectDashboardMixin, Simpl
332
331
  "missed_visit",
333
332
  "auto_resolved",
334
333
  "registered_subject",
335
- ) + action_fields
334
+ *action_fields,
335
+ )
336
336
  if not request.user.groups.filter(name=DATA_MANAGER):
337
337
  extra_fields = (
338
338
  "data_dictionaries",
@@ -350,10 +350,11 @@ class DataQueryAdmin(SiteModelAdminMixin, ModelAdminSubjectDashboardMixin, Simpl
350
350
  "title",
351
351
  "visit_code_sequence",
352
352
  "visit_schedule",
353
+ *extra_fields,
353
354
  )
354
355
  if not obj:
355
356
  extra_fields = tuple(f for f in extra_fields if f != "registered_subject")
356
- return fields + extra_fields
357
+ return *fields, *extra_fields
357
358
 
358
359
  def get_subject_dashboard_url_kwargs(self, obj):
359
360
  def get_opts():