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
@@ -2,17 +2,17 @@ from django.core.exceptions import ObjectDoesNotExist
2
2
  from django.db import transaction
3
3
  from django.db.models.signals import m2m_changed, post_delete, post_save
4
4
  from django.dispatch.dispatcher import receiver
5
+ from django.utils import timezone
5
6
 
6
7
  from edc_constants.constants import NO, YES
7
8
  from edc_notification.models import Notification
8
- from edc_utils import get_utcnow
9
9
 
10
10
  from ..constants import AE_TMG_ACTION, DEATH_REPORT_TMG_ACTION, TMG
11
11
  from ..utils import get_ae_model
12
12
 
13
13
 
14
14
  @receiver(m2m_changed, weak=False, dispatch_uid="update_ae_notifications_for_tmg_group")
15
- def update_ae_notifications_for_tmg_group(action, instance, **kwargs): # noqa: ARG001
15
+ def update_ae_notifications_for_tmg_group(action, instance, **kwargs):
16
16
  if getattr(instance, "userprofile", None):
17
17
  try:
18
18
  tmg_ae_notification = Notification.objects.get(name=AE_TMG_ACTION)
@@ -29,7 +29,7 @@ def update_ae_notifications_for_tmg_group(action, instance, **kwargs): # noqa:
29
29
 
30
30
 
31
31
  @receiver(post_save, weak=False, dispatch_uid="update_ae_initial_for_susar")
32
- def update_ae_initial_for_susar(sender, instance, raw, update_fields, **kwargs): # noqa: ARG001
32
+ def update_ae_initial_for_susar(sender, instance, raw, update_fields, **kwargs):
33
33
  if not raw and not update_fields:
34
34
  try:
35
35
  ae_susar_model_cls = get_ae_model("AeSusar")
@@ -55,7 +55,7 @@ def update_ae_initial_for_susar(sender, instance, raw, update_fields, **kwargs):
55
55
  weak=False,
56
56
  dispatch_uid="update_ae_initial_susar_reported",
57
57
  )
58
- def update_ae_initial_susar_reported(sender, instance, raw, update_fields, **kwargs): # noqa: ARG001
58
+ def update_ae_initial_susar_reported(sender, instance, raw, update_fields, **kwargs):
59
59
  if not raw and not update_fields:
60
60
  try:
61
61
  ae_initial_model_cls = get_ae_model("AeInitial")
@@ -72,12 +72,12 @@ def update_ae_initial_susar_reported(sender, instance, raw, update_fields, **kwa
72
72
  ae_susar_model_cls.objects.get(ae_initial=instance)
73
73
  except ObjectDoesNotExist:
74
74
  ae_susar_model_cls.objects.create(
75
- ae_initial=instance, submitted_datetime=get_utcnow()
75
+ ae_initial=instance, submitted_datetime=timezone.now()
76
76
  )
77
77
 
78
78
 
79
79
  @receiver(post_delete, weak=False, dispatch_uid="post_delete_ae_susar")
80
- def post_delete_ae_susar(instance, **kwargs): # noqa: ARG001
80
+ def post_delete_ae_susar(instance, **kwargs):
81
81
  try:
82
82
  ae_susar_model_cls = get_ae_model("AeSusar")
83
83
  except LookupError:
@@ -93,7 +93,7 @@ def post_delete_ae_susar(instance, **kwargs): # noqa: ARG001
93
93
 
94
94
 
95
95
  @receiver(m2m_changed, weak=False, dispatch_uid="update_death_notifications_for_tmg_group")
96
- def update_death_notifications_for_tmg_group(action, instance, **kwargs): # noqa: ARG001
96
+ def update_death_notifications_for_tmg_group(action, instance, **kwargs):
97
97
  if getattr(instance, "userprofile", None):
98
98
  try:
99
99
  tmg_death_notification = Notification.objects.get(name=DEATH_REPORT_TMG_ACTION)
@@ -10,6 +10,7 @@ from django.conf import settings
10
10
  from django.contrib.messages import ERROR
11
11
  from django.core.exceptions import ObjectDoesNotExist
12
12
  from django.template.loader import select_template
13
+ from django.utils import timezone
13
14
  from django.utils.html import format_html
14
15
  from django.utils.safestring import mark_safe
15
16
  from django.utils.translation import gettext as _
@@ -17,7 +18,7 @@ from django.utils.translation import gettext as _
17
18
  from edc_action_item.utils import get_reference_obj
18
19
  from edc_constants.constants import CLOSED, OPEN, OTHER, YES
19
20
  from edc_model_admin.utils import add_to_messages_once
20
- from edc_utils import escape_braces, get_utcnow
21
+ from edc_utils import escape_braces
21
22
 
22
23
  from ..constants import (
23
24
  AE_TMG_ACTION,
@@ -81,7 +82,7 @@ def select_description_template(model):
81
82
 
82
83
  @register.inclusion_tag(select_description_template("aeinitial"), takes_context=True)
83
84
  def format_ae_description(context, ae_initial, wrap_length):
84
- context["utc_date"] = get_utcnow().date()
85
+ context["utc_date"] = timezone.now().date()
85
86
  context["SHORT_DATE_FORMAT"] = settings.SHORT_DATE_FORMAT
86
87
  context["OTHER"] = OTHER
87
88
  context["YES"] = YES
@@ -103,7 +104,7 @@ def format_ae_description(context, ae_initial, wrap_length):
103
104
  @register.inclusion_tag(select_description_template("aefollowup"), takes_context=True)
104
105
  def format_ae_followup_description(context, ae_followup, wrap_length):
105
106
  context["AE_WITHDRAWN"] = AE_WITHDRAWN
106
- context["utc_date"] = get_utcnow().date()
107
+ context["utc_date"] = timezone.now().date()
107
108
  context["SHORT_DATE_FORMAT"] = settings.SHORT_DATE_FORMAT
108
109
  context["OTHER"] = OTHER
109
110
  context["YES"] = YES
@@ -131,7 +132,7 @@ def format_ae_followup_description(context, ae_followup, wrap_length):
131
132
 
132
133
  @register.inclusion_tag(select_description_template("aesusar"), takes_context=True)
133
134
  def format_ae_susar_description(context, ae_susar, wrap_length):
134
- context["utc_date"] = get_utcnow().date()
135
+ context["utc_date"] = timezone.now().date()
135
136
  context["SHORT_DATE_FORMAT"] = settings.SHORT_DATE_FORMAT
136
137
  context["OTHER"] = OTHER
137
138
  context["YES"] = YES
@@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Any
4
4
 
5
5
  from django.core.exceptions import ObjectDoesNotExist
6
6
  from django.template.loader import render_to_string
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
 
@@ -12,7 +13,6 @@ from edc_dashboard.view_mixins import EdcViewMixin
12
13
  from edc_listboard.view_mixins import ListboardFilterViewMixin, SearchFormViewMixin
13
14
  from edc_listboard.views import ListboardView as BaseListboardView
14
15
  from edc_navbar import NavbarViewMixin
15
- from edc_utils import get_utcnow
16
16
 
17
17
  from ...constants import AE_INITIAL_ACTION
18
18
  from ...pdf_reports import AePdfReport
@@ -43,9 +43,7 @@ class AeListboardViewMixin(
43
43
 
44
44
  listboard_instructions = format_html(
45
45
  "{}",
46
- mark_safe(
47
- render_to_string("edc_adverse_event/ae/ae_listboard_instructions.html")
48
- ), # nosec B703 B308,
46
+ mark_safe(render_to_string("edc_adverse_event/ae/ae_listboard_instructions.html")), # nosec B703 B308,
49
47
  )
50
48
  navbar_selected_item = "ae_home"
51
49
  ordering = "-report_datetime"
@@ -78,7 +76,7 @@ class AeListboardViewMixin(
78
76
  def get_context_data(self, **kwargs) -> dict[str, Any]:
79
77
  kwargs.update(
80
78
  AE_INITIAL_ACTION=AE_INITIAL_ACTION,
81
- utc_date=get_utcnow().date(),
79
+ utc_date=timezone.now().date(),
82
80
  **self.add_url_to_context(
83
81
  new_key="ae_home_url",
84
82
  existing_key=self.home_url,
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  from typing import TYPE_CHECKING, Any
4
4
 
5
5
  from django.core.exceptions import ObjectDoesNotExist
6
+ from django.utils import timezone
6
7
  from django.utils.html import format_html
7
8
  from django.utils.safestring import mark_safe
8
9
 
@@ -11,7 +12,6 @@ from edc_dashboard.view_mixins import EdcViewMixin
11
12
  from edc_listboard.view_mixins import ListboardFilterViewMixin, SearchFormViewMixin
12
13
  from edc_listboard.views import ListboardView as BaseListboardView
13
14
  from edc_navbar import NavbarViewMixin
14
- from edc_utils import get_utcnow
15
15
 
16
16
  from ...constants import DEATH_REPORT_ACTION
17
17
  from ...pdf_reports import DeathPdfReport
@@ -40,25 +40,23 @@ class DeathReportListboardViewMixin(
40
40
  listboard_view_permission_codename = "edc_adverse_event.view_ae_listboard"
41
41
  listboard_instructions = format_html(
42
42
  "{}",
43
- mark_safe(
44
- "edc_adverse_event/ae/death_report_listboard_instructions.html"
45
- ), # nosec B703 B308
43
+ mark_safe("edc_adverse_event/ae/death_report_listboard_instructions.html"), # nosec B703 B308
46
44
  )
47
45
 
48
46
  navbar_selected_item = "ae_home"
49
47
  ordering = "-report_datetime"
50
48
  paginate_by = 25
51
49
  search_form_url = "death_report_listboard_url"
52
- action_type_names = [DEATH_REPORT_ACTION]
50
+ action_type_names = (DEATH_REPORT_ACTION,)
53
51
 
54
- search_fields = [
52
+ search_fields = (
55
53
  "subject_identifier",
56
54
  "action_identifier",
57
55
  "parent_action_item__action_identifier",
58
56
  "related_action_item__action_identifier",
59
57
  "user_created",
60
58
  "user_modified",
61
- ]
59
+ )
62
60
 
63
61
  def get(self, request, *args, **kwargs):
64
62
  if request.GET.get("pdf"):
@@ -71,7 +69,7 @@ class DeathReportListboardViewMixin(
71
69
  def get_context_data(self, **kwargs) -> dict[str, Any]:
72
70
  kwargs.update(
73
71
  DEATH_REPORT_ACTION=DEATH_REPORT_ACTION,
74
- utc_date=get_utcnow().date(),
72
+ utc_date=timezone.now().date(),
75
73
  **self.add_url_to_context(
76
74
  new_key="ae_home_url",
77
75
  existing_key=self.home_url,
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  from typing import TYPE_CHECKING, Any
4
4
 
5
5
  from django.db.models import Min
6
+ from django.utils import timezone
6
7
 
7
8
  from edc_constants.constants import CLOSED, NEW, OPEN
8
9
  from edc_dashboard.view_mixins import EdcViewMixin
@@ -10,7 +11,6 @@ from edc_listboard.view_mixins import ListboardFilterViewMixin, SearchFormViewMi
10
11
  from edc_listboard.views import ListboardView as BaseListboardView
11
12
  from edc_navbar import NavbarViewMixin
12
13
  from edc_navbar.get_default_navbar import get_default_navbar
13
- from edc_utils import get_utcnow
14
14
 
15
15
  from ...constants import (
16
16
  AE_TMG_ACTION,
@@ -69,7 +69,7 @@ class TmgAeListboardViewMixin(
69
69
  def get_context_data(self, **kwargs) -> dict[str, Any]:
70
70
  kwargs.update(
71
71
  AE_TMG_ACTION=AE_TMG_ACTION,
72
- utc_date=get_utcnow().date(),
72
+ utc_date=timezone.now().date(),
73
73
  subject_identifier=self.kwargs.get("subject_identifier"),
74
74
  )
75
75
  return super().get_context_data(**kwargs)
@@ -2,11 +2,12 @@ from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING, Any
4
4
 
5
+ from django.utils import timezone
6
+
5
7
  from edc_dashboard.view_mixins import EdcViewMixin
6
8
  from edc_listboard.view_mixins import ListboardFilterViewMixin, SearchFormViewMixin
7
9
  from edc_listboard.views import ListboardView as BaseListboardView
8
10
  from edc_navbar import NavbarViewMixin
9
- from edc_utils import get_utcnow
10
11
 
11
12
  from ...constants import (
12
13
  AE_FOLLOWUP_ACTION,
@@ -57,7 +58,7 @@ class SummaryListboardView(
57
58
  ]
58
59
 
59
60
  def get_context_data(self, **kwargs) -> dict[str, Any]:
60
- kwargs.update(AE_TMG_ACTION=AE_TMG_ACTION, utc_date=get_utcnow().date())
61
+ kwargs.update(AE_TMG_ACTION=AE_TMG_ACTION, utc_date=timezone.now().date())
61
62
  return super().get_context_data(**kwargs)
62
63
 
63
64
  def get_queryset_filter_options(self, request, *args, **kwargs) -> tuple[Q, dict]:
@@ -7,6 +7,7 @@ from django.contrib import admin
7
7
  from django.db.models import DurationField, ExpressionWrapper, F
8
8
  from django.template.loader import render_to_string
9
9
  from django.urls import reverse
10
+ from django.utils import timezone
10
11
  from django.utils.html import format_html
11
12
  from django.utils.translation import gettext as _
12
13
  from django_audit_fields.admin import audit_fieldset_tuple
@@ -19,7 +20,6 @@ from edc_document_status.modeladmin_mixins import DocumentStatusModelAdminMixin
19
20
  from edc_model_admin.dashboard import ModelAdminSubjectDashboardMixin
20
21
  from edc_model_admin.history import SimpleHistoryAdmin
21
22
  from edc_sites.admin import SiteModelAdminMixin
22
- from edc_utils import get_utcnow
23
23
  from edc_visit_schedule.admin import ScheduleStatusListFilter
24
24
  from edc_visit_schedule.exceptions import OnScheduleError
25
25
  from edc_visit_schedule.fieldsets import (
@@ -290,7 +290,7 @@ class AppointmentAdmin(
290
290
 
291
291
  def get_queryset(self, request):
292
292
  qs = super().get_queryset(request)
293
- now = get_utcnow().replace(second=59, hour=23, minute=59)
293
+ now = timezone.now().replace(second=59, hour=23, minute=59)
294
294
  return qs.annotate(
295
295
  appt_timepoint_delta=ExpressionWrapper(
296
296
  (F("appt_datetime") - F("timepoint_datetime")),
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  from dateutil.relativedelta import relativedelta
4
4
  from django.contrib.admin import SimpleListFilter
5
5
  from django.db.models import QuerySet
6
+ from django.utils import timezone
6
7
  from django.utils.translation import gettext as _
7
8
 
8
9
  from edc_appointment.choices import APPT_STATUS
@@ -18,7 +19,6 @@ from edc_appointment.constants import (
18
19
  LT_30_DAYS,
19
20
  )
20
21
  from edc_model_admin.list_filters import FutureDateListFilter
21
- from edc_utils import get_utcnow
22
22
 
23
23
 
24
24
  class AppointmentListFilter(FutureDateListFilter):
@@ -62,7 +62,7 @@ class AppointmentOverdueListFilter(SimpleListFilter):
62
62
  )
63
63
 
64
64
  def queryset(self, request, queryset) -> QuerySet | None:
65
- now = get_utcnow().replace(second=59, hour=23, minute=59)
65
+ now = timezone.now().replace(second=59, hour=23, minute=59)
66
66
  qs = None
67
67
  if self.value() == LT_30_DAYS:
68
68
  qs = queryset.filter(
edc_appointment/auths.py CHANGED
@@ -8,17 +8,21 @@ from edc_auth.site_auths import site_auths
8
8
 
9
9
  from .auth_objects import APPOINTMENT, APPOINTMENT_EXPORT, APPOINTMENT_VIEW, codenames
10
10
 
11
- site_auths.add_group(*codenames, name=APPOINTMENT_VIEW, view_only=True)
12
11
 
13
- site_auths.add_group(*codenames, name=APPOINTMENT)
12
+ def update_site_auths():
13
+ site_auths.add_group(*codenames, name=APPOINTMENT_VIEW, view_only=True)
14
14
 
15
- site_auths.add_group(
16
- "edc_appointment.export_appointment",
17
- name=APPOINTMENT_EXPORT,
18
- )
15
+ site_auths.add_group(*codenames, name=APPOINTMENT)
16
+
17
+ site_auths.add_group(
18
+ "edc_appointment.export_appointment",
19
+ name=APPOINTMENT_EXPORT,
20
+ )
21
+
22
+ site_auths.update_role(APPOINTMENT, name=CLINICIAN_ROLE)
23
+ site_auths.update_role(APPOINTMENT, name=NURSE_ROLE)
24
+ site_auths.update_role(APPOINTMENT_VIEW, name=AUDITOR_ROLE)
25
+ site_auths.update_role(APPOINTMENT, name=CLINICIAN_SUPER_ROLE)
19
26
 
20
27
 
21
- site_auths.update_role(APPOINTMENT, name=CLINICIAN_ROLE)
22
- site_auths.update_role(APPOINTMENT, name=NURSE_ROLE)
23
- site_auths.update_role(APPOINTMENT_VIEW, name=AUDITOR_ROLE)
24
- site_auths.update_role(APPOINTMENT, name=CLINICIAN_SUPER_ROLE)
28
+ update_site_auths()
@@ -215,7 +215,7 @@ class AppointmentCreator:
215
215
  raise CreateAppointmentDateError(
216
216
  f"{e} Visit={self.visit!r}. "
217
217
  f"Try setting 'best_effort_available_datetime=True' on facility."
218
- )
218
+ ) from e
219
219
  else:
220
220
  return self.suggested_datetime
221
221
  return arw.datetime
@@ -85,7 +85,7 @@ class AppointmentsCreator:
85
85
  except FacilityError as e:
86
86
  raise CreateAppointmentError(
87
87
  f"{e} See {visit!r}. Got facility_name={visit.facility_name}"
88
- )
88
+ ) from e
89
89
  appointment = self.update_or_create_appointment(
90
90
  visit=visit,
91
91
  taken_datetimes=taken_datetimes,
@@ -6,6 +6,7 @@ from typing import TYPE_CHECKING, Any
6
6
  from django.apps import apps as django_apps
7
7
  from django.conf import settings
8
8
  from django.urls import reverse
9
+ from django.utils import timezone
9
10
  from django.utils.html import format_html
10
11
  from django.utils.safestring import mark_safe
11
12
  from django.utils.translation import gettext_lazy as _
@@ -16,7 +17,7 @@ from edc_form_validators import INVALID_ERROR
16
17
  from edc_form_validators.form_validator import FormValidator
17
18
  from edc_metadata.metadata_helper import MetadataHelperMixin
18
19
  from edc_sites.form_validator_mixin import SiteFormValidatorMixin
19
- from edc_utils import formatted_datetime, get_utcnow, to_utc
20
+ from edc_utils import formatted_datetime, to_utc
20
21
  from edc_utils.date import to_local
21
22
  from edc_visit_schedule.site_visit_schedules import site_visit_schedules
22
23
  from edc_visit_schedule.subject_schedule import NotOnScheduleError
@@ -136,19 +137,23 @@ class AppointmentFormValidator(
136
137
  self.instance, "id", None
137
138
  ):
138
139
  previous_appt = get_previous_appointment(self.instance, include_interim=True)
139
- if previous_appt and previous_appt.appt_status not in [
140
- CANCELLED_APPT,
141
- SKIPPED_APPT,
142
- ]:
143
- if not previous_appt.related_visit:
144
- self.raise_validation_error(
145
- message=(
146
- "A previous appointment requires a visit report. "
147
- f"Update appointment {previous_appt.visit_code}."
148
- f"{previous_appt.visit_code_sequence} first."
149
- ),
150
- error_code=INVALID_PREVIOUS_VISIT_MISSING,
151
- )
140
+ if (
141
+ previous_appt
142
+ and previous_appt.appt_status
143
+ not in [
144
+ CANCELLED_APPT,
145
+ SKIPPED_APPT,
146
+ ]
147
+ and not previous_appt.related_visit
148
+ ):
149
+ self.raise_validation_error(
150
+ message=(
151
+ "A previous appointment requires a visit report. "
152
+ f"Update appointment {previous_appt.visit_code}."
153
+ f"{previous_appt.visit_code_sequence} first."
154
+ ),
155
+ error_code=INVALID_PREVIOUS_VISIT_MISSING,
156
+ )
152
157
  return True
153
158
 
154
159
  def validate_appt_sequence(self: Any) -> bool:
@@ -158,33 +163,45 @@ class AppointmentFormValidator(
158
163
  Check if previous appointment appt_status is NEW_APPT
159
164
 
160
165
  """
161
- if self.cleaned_data.get("appt_status") in [
162
- IN_PROGRESS_APPT,
163
- INCOMPLETE_APPT,
164
- COMPLETE_APPT,
165
- ]:
166
- if self.instance.previous:
167
- if obj := (
168
- self.appointment_model_cls.objects.filter(
169
- subject_identifier=self.subject_identifier,
170
- visit_schedule_name=self.instance.visit_schedule_name,
171
- schedule_name=self.instance.schedule_name,
172
- appt_status=NEW_APPT,
173
- appt_datetime__lt=self.instance.appt_datetime,
174
- )
175
- .order_by("timepoint", "visit_code_sequence")
176
- .first()
177
- ):
178
- self.raise_validation_error(
179
- {
180
- "__all__": _(
181
- "A previous appointment requires updating. "
182
- f"Update appointment {obj.visit_code}."
183
- f"{obj.visit_code_sequence} first."
184
- )
185
- },
186
- INVALID_PREVIOUS_APPOINTMENT_NOT_UPDATED,
166
+ if (
167
+ self.cleaned_data.get("appt_status")
168
+ in [
169
+ IN_PROGRESS_APPT,
170
+ INCOMPLETE_APPT,
171
+ COMPLETE_APPT,
172
+ ]
173
+ and self.instance.previous
174
+ ) and (
175
+ obj := (
176
+ self.appointment_model_cls.objects.filter(
177
+ subject_identifier=self.subject_identifier,
178
+ visit_schedule_name=self.instance.visit_schedule_name,
179
+ schedule_name=self.instance.schedule_name,
180
+ appt_status=NEW_APPT,
181
+ appt_datetime__lt=self.instance.appt_datetime,
182
+ )
183
+ .order_by("timepoint", "visit_code_sequence")
184
+ .first()
185
+ )
186
+ ):
187
+ errmsg = (
188
+ "A previous appointment requires updating. "
189
+ "Update appointment %(visit_code)s."
190
+ "%(visit_code_sequence)s first."
191
+ )
192
+
193
+ self.raise_validation_error(
194
+ {
195
+ "__all__": _(
196
+ errmsg
197
+ % dict(
198
+ visit_code=obj.visit_code,
199
+ visit_code_sequence=obj.visit_code_sequence,
200
+ )
187
201
  )
202
+ },
203
+ INVALID_PREVIOUS_APPOINTMENT_NOT_UPDATED,
204
+ )
188
205
  return True
189
206
 
190
207
  def validate_timepoint(self: Any):
@@ -202,12 +219,15 @@ class AppointmentFormValidator(
202
219
  def validate_not_future_appt_datetime(self: Any) -> None:
203
220
  appt_datetime = self.cleaned_data.get("appt_datetime")
204
221
  appt_status = self.cleaned_data.get("appt_status")
205
- if appt_datetime and appt_status != NEW_APPT:
206
- if to_utc(appt_datetime) > get_utcnow():
207
- self.raise_validation_error(
208
- {"appt_datetime": "Cannot be a future date/time."},
209
- INVALID_APPT_DATE,
210
- )
222
+ if (
223
+ appt_datetime
224
+ and appt_status != NEW_APPT
225
+ and to_utc(appt_datetime) > timezone.now()
226
+ ):
227
+ self.raise_validation_error(
228
+ {"appt_datetime": "Cannot be a future date/time."},
229
+ INVALID_APPT_DATE,
230
+ )
211
231
 
212
232
  def validate_appt_datetime_not_before_consent_datetime(self: Any) -> None:
213
233
  if (
@@ -291,42 +311,46 @@ class AppointmentFormValidator(
291
311
  def validate_appt_datetime_not_before_previous_appt_datetime(self):
292
312
  appt_datetime = self.cleaned_data.get("appt_datetime")
293
313
  appt_status = self.cleaned_data.get("appt_status")
294
- if appt_datetime and appt_status and appt_status != NEW_APPT:
295
- if self.instance.relative_previous:
296
- if to_utc(appt_datetime) < self.instance.relative_previous.appt_datetime:
297
- formatted_date = formatted_datetime(
298
- self.instance.relative_previous.appt_datetime
299
- )
300
- self.raise_validation_error(
301
- {
302
- "appt_datetime": (
303
- "Cannot be before previous appointment. Previous appointment "
304
- f"is {self.instance.relative_previous.visit_label} "
305
- f"on {formatted_date}."
306
- )
307
- },
308
- INVALID_APPT_DATE,
314
+ if (
315
+ appt_datetime
316
+ and appt_status
317
+ and appt_status != NEW_APPT
318
+ and self.instance.relative_previous
319
+ and to_utc(appt_datetime) < self.instance.relative_previous.appt_datetime
320
+ ):
321
+ formatted_date = formatted_datetime(self.instance.relative_previous.appt_datetime)
322
+ self.raise_validation_error(
323
+ {
324
+ "appt_datetime": (
325
+ "Cannot be before previous appointment. Previous appointment "
326
+ f"is {self.instance.relative_previous.visit_label} "
327
+ f"on {formatted_date}."
309
328
  )
329
+ },
330
+ INVALID_APPT_DATE,
331
+ )
310
332
 
311
333
  def validate_appt_datetime_not_after_next_appt_datetime(self) -> None:
312
334
  appt_datetime = self.cleaned_data.get("appt_datetime")
313
335
  appt_status = self.cleaned_data.get("appt_status")
314
- if appt_datetime and appt_status and appt_status != NEW_APPT:
315
- if self.instance.relative_next:
316
- if to_utc(appt_datetime) > self.instance.relative_next.appt_datetime:
317
- formatted_date = formatted_datetime(
318
- self.instance.relative_next.appt_datetime
319
- )
320
- self.raise_validation_error(
321
- {
322
- "appt_datetime": (
323
- "Cannot be after next appointment. Next appointment is "
324
- f"{self.instance.relative_next.visit_label} "
325
- f"on {formatted_date}."
326
- )
327
- },
328
- INVALID_APPT_DATE,
336
+ if (
337
+ appt_datetime
338
+ and appt_status
339
+ and appt_status != NEW_APPT
340
+ and self.instance.relative_next
341
+ and to_utc(appt_datetime) > self.instance.relative_next.appt_datetime
342
+ ):
343
+ formatted_date = formatted_datetime(self.instance.relative_next.appt_datetime)
344
+ self.raise_validation_error(
345
+ {
346
+ "appt_datetime": (
347
+ "Cannot be after next appointment. Next appointment is "
348
+ f"{self.instance.relative_next.visit_label} "
349
+ f"on {formatted_date}."
329
350
  )
351
+ },
352
+ INVALID_APPT_DATE,
353
+ )
330
354
 
331
355
  def validate_appt_incomplete_and_visit_report(self: Any) -> None:
332
356
  """Require a visit report, at least, if wanting to set appt_status
@@ -502,12 +526,14 @@ class AppointmentFormValidator(
502
526
 
503
527
  Is this still used?
504
528
  """
505
- if self.cleaned_data.get("facility_name"):
506
- if self.cleaned_data.get("facility_name") not in get_facilities():
507
- self.raise_validation_error(
508
- {"__all__": f"Facility '{self.facility_name}' does not exist."},
509
- INVALID_ERROR,
510
- )
529
+ if (
530
+ self.cleaned_data.get("facility_name")
531
+ and self.cleaned_data.get("facility_name") not in get_facilities()
532
+ ):
533
+ self.raise_validation_error(
534
+ {"__all__": f"Facility '{self.facility_name}' does not exist."},
535
+ INVALID_ERROR,
536
+ )
511
537
 
512
538
  def validate_appt_type(self):
513
539
  self.not_applicable_if(SKIPPED_APPT, field="appt_status", field_applicable="appt_type")
@@ -3,8 +3,7 @@
3
3
  from __future__ import unicode_literals
4
4
 
5
5
  from django.db import migrations, models
6
-
7
- import edc_utils
6
+ import django.utils.timezone
8
7
 
9
8
 
10
9
  class Migration(migrations.Migration):
@@ -16,22 +15,22 @@ class Migration(migrations.Migration):
16
15
  migrations.AlterField(
17
16
  model_name="appointment",
18
17
  name="created",
19
- field=models.DateTimeField(default=edc_utils.date.get_utcnow, editable=False),
18
+ field=models.DateTimeField(default=django.utils.timezone.now, editable=False),
20
19
  ),
21
20
  migrations.AlterField(
22
21
  model_name="appointment",
23
22
  name="modified",
24
- field=models.DateTimeField(default=edc_utils.date.get_utcnow, editable=False),
23
+ field=models.DateTimeField(default=django.utils.timezone.now, editable=False),
25
24
  ),
26
25
  migrations.AlterField(
27
26
  model_name="historicalappointment",
28
27
  name="created",
29
- field=models.DateTimeField(default=edc_utils.date.get_utcnow, editable=False),
28
+ field=models.DateTimeField(default=django.utils.timezone.now, editable=False),
30
29
  ),
31
30
  migrations.AlterField(
32
31
  model_name="historicalappointment",
33
32
  name="modified",
34
- field=models.DateTimeField(default=edc_utils.date.get_utcnow, editable=False),
33
+ field=models.DateTimeField(default=django.utils.timezone.now, editable=False),
35
34
  ),
36
35
  migrations.AlterUniqueTogether(name="appointment", unique_together=set([])),
37
36
  migrations.RemoveField(model_name="appointment", name="consent_version"),