clinicedc 2.0.5__py3-none-any.whl → 2.0.7__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 (387) hide show
  1. {clinicedc-2.0.5.dist-info → clinicedc-2.0.7.dist-info}/METADATA +2 -2
  2. {clinicedc-2.0.5.dist-info → clinicedc-2.0.7.dist-info}/RECORD +387 -336
  3. edc_action_item/action.py +1 -1
  4. edc_action_item/action_item_notification.py +2 -2
  5. edc_action_item/create_action_item.py +1 -1
  6. edc_action_item/decorators.py +1 -1
  7. edc_action_item/migrations/0001_initial.py +21 -22
  8. edc_action_item/migrations/0006_auto_20180707_1659.py +4 -4
  9. edc_action_item/migrations/0008_auto_20180809_0303.py +4 -4
  10. edc_action_item/migrations/0015_auto_20190114_0250.py +4 -4
  11. edc_action_item/migrations/0017_auto_20190305_0123.py +11 -30
  12. edc_action_item/migrations/0030_edcpermissions.py +3 -2
  13. edc_action_item/migrations/0039_alter_actionitem_auto_created_comment_and_more.py +398 -0
  14. edc_action_item/migrations/0040_alter_actionitem_report_datetime_and_more.py +34 -0
  15. edc_action_item/models/action_item.py +9 -4
  16. edc_action_item/models/action_model_mixin.py +4 -4
  17. edc_action_item/models/reference.py +2 -2
  18. edc_action_item/post_migrate_signals.py +1 -1
  19. edc_action_item/send_email.py +0 -85
  20. edc_adherence/migrations/0005_alter_nonadherencereasons_extra_value_and_more.py +36 -0
  21. edc_adherence/model_mixins.py +1 -1
  22. edc_adverse_event/migrations/0001_initial.py +5 -4
  23. edc_adverse_event/migrations/0002_auto_20190802_0059.py +3 -2
  24. edc_adverse_event/migrations/0008_auto_20220825_0451.py +3 -2
  25. edc_adverse_event/migrations/0009_auto_20220907_0157.py +3 -2
  26. edc_adverse_event/migrations/0016_alter_aeactionclassification_device_created_and_more.py +285 -0
  27. edc_adverse_event/model_mixins/ae_followup/ae_followup_fields_model_mixin.py +2 -2
  28. edc_adverse_event/model_mixins/ae_initial/ae_initial_fields_model_mixin.py +6 -5
  29. edc_adverse_event/model_mixins/ae_special_interest/aesi_fields_model_mixin.py +2 -2
  30. edc_adverse_event/model_mixins/ae_susar/ae_susar_fields_model_mixin.py +2 -2
  31. edc_adverse_event/model_mixins/ae_tmg/ae_tmg_fields_model_mixin.py +15 -11
  32. edc_adverse_event/model_mixins/death_report/death_report_model_mixin.py +5 -4
  33. edc_adverse_event/model_mixins/death_report/death_report_tmg_model_mixin.py +6 -3
  34. edc_adverse_event/model_mixins/death_report/simple_death_report_model_mixin.py +2 -2
  35. edc_adverse_event/model_mixins/hospitaization/hospitalization_model_mixin.py +4 -3
  36. edc_adverse_event/modeladmin_mixins/death_report_admin_mixin.py +3 -3
  37. edc_adverse_event/models/signals.py +7 -7
  38. edc_adverse_event/templatetags/edc_adverse_event_extras.py +5 -4
  39. edc_adverse_event/view_mixins/ae/ae_listboard_view_mixin.py +3 -5
  40. edc_adverse_event/view_mixins/ae/death_report_listboard_view_mixin.py +6 -8
  41. edc_adverse_event/view_mixins/tmg/tmg_ae_listboard_view_mixin.py +2 -2
  42. edc_adverse_event/views/tmg/summary_listboard_view.py +3 -2
  43. edc_appointment/admin/appointment_admin.py +2 -2
  44. edc_appointment/admin/list_filters.py +2 -2
  45. edc_appointment/form_validators/appointment_form_validator.py +108 -82
  46. edc_appointment/migrations/0003_auto_20161127_2226.py +5 -6
  47. edc_appointment/migrations/0006_auto_20170106_2118.py +5 -5
  48. edc_appointment/migrations/0018_auto_20190305_0123.py +5 -12
  49. edc_appointment/migrations/0050_alter_appointment_appt_type_and_more.py +220 -0
  50. edc_appointment/model_mixins/appointment_fields_model_mixin.py +1 -2
  51. edc_appointment/model_mixins/window_period_model_mixin.py +6 -7
  52. edc_appointment/models/signals.py +44 -35
  53. edc_appointment/view_utils/appointment_button.py +2 -2
  54. edc_auth/admin/user_admin.py +1 -1
  55. edc_auth/migrations/0001_squashed_0033_alter_userprofile_is_multisite_viewer.py +5 -5
  56. edc_auth/migrations/0012_auto_20191026_0034.py +3 -2
  57. edc_auth/migrations/0013_auto_20191026_0055.py +3 -2
  58. edc_auth/migrations/0025_permissions.py +3 -2
  59. edc_auth/migrations/0035_alter_edcpermissions_device_created_and_more.py +85 -0
  60. edc_auth/post_migrate_signals.py +1 -1
  61. edc_consent/actions.py +4 -5
  62. edc_consent/migrations/0001_initial.py +3 -2
  63. edc_consent/migrations/0006_alter_edcpermissions_device_created_and_more.py +49 -0
  64. edc_consent/model_mixins/consent_extension_model_mixin.py +4 -5
  65. edc_consent/model_mixins/requires_consent_fields_model_mixin.py +2 -2
  66. edc_consent/utils.py +1 -1
  67. edc_crf/migrations/0001_initial.py +3 -2
  68. edc_crf/migrations/0009_alter_crfstatus_device_created_and_more.py +54 -0
  69. edc_dashboard/migrations/0001_initial.py +3 -2
  70. edc_dashboard/migrations/0006_alter_edcpermissions_device_created_and_more.py +49 -0
  71. edc_dashboard/templatetags/edc_dashboard_extras.py +3 -2
  72. edc_data_manager/action_items.py +4 -6
  73. edc_data_manager/admin/actions.py +5 -5
  74. edc_data_manager/handlers/handlers.py +6 -7
  75. edc_data_manager/migrations/0001_initial.py +19 -19
  76. edc_data_manager/migrations/0025_edcpermissions.py +3 -2
  77. edc_data_manager/migrations/0040_alter_datadictionary_device_created_and_more.py +327 -0
  78. edc_data_manager/migrations/0041_alter_dataquery_dm_user_and_more.py +164 -0
  79. edc_data_manager/models/data_query.py +5 -5
  80. edc_data_manager/models/model_mixins.py +8 -8
  81. edc_data_manager/rule/rule_runner.py +4 -3
  82. edc_document_status/model_mixins.py +1 -1
  83. edc_egfr/egfr.py +11 -7
  84. edc_egfr/model_mixins/egfr_model_mixin.py +3 -7
  85. edc_export/admin/data_request_admin.py +2 -2
  86. edc_export/archive_exporter.py +4 -3
  87. edc_export/files_archiver.py +3 -2
  88. edc_export/migrations/0001_initial.py +26 -26
  89. edc_export/migrations/0004_auto_20190305_0123.py +25 -72
  90. edc_export/migrations/0013_edcpermissions.py +3 -2
  91. edc_export/migrations/0022_alter_datarequest_description_and_more.py +611 -0
  92. edc_export/migrations/0023_alter_datarequesthistory_archive_filename_and_more.py +29 -0
  93. edc_export/model_exporter/file_history_updater.py +10 -10
  94. edc_export/model_exporter/model_exporter.py +13 -14
  95. edc_export/model_exporter/object_history_helpers.py +2 -2
  96. edc_export/models/data_request_history.py +4 -4
  97. edc_export/utils.py +10 -15
  98. edc_facility/facility.py +10 -15
  99. edc_facility/import_holidays.py +13 -13
  100. edc_facility/migrations/0005_healthfacility_healthfacilitytypes_and_more.py +8 -7
  101. edc_facility/migrations/0016_alter_healthfacility_device_created_and_more.py +139 -0
  102. edc_facility/migrations/0017_alter_healthfacility_gps_and_more.py +54 -0
  103. edc_facility/model_mixins.py +5 -5
  104. edc_form_runners/form_runner.py +3 -5
  105. edc_form_runners/migrations/0001_initial.py +3 -2
  106. edc_form_runners/migrations/0005_alter_issue_device_created_and_more.py +49 -0
  107. edc_identifier/migrations/0001_squashed_0018_auto_20180128_1054.py +3 -3
  108. edc_identifier/migrations/0002_auto_20190305_0123.py +3 -6
  109. edc_identifier/migrations/0006_auto_20161127_2226.py +15 -15
  110. edc_identifier/migrations/0007_auto_20161204_2227.py +3 -3
  111. edc_identifier/migrations/0009_auto_20161221_2323.py +3 -5
  112. edc_identifier/migrations/0010_auto_20170112_0602.py +17 -17
  113. edc_identifier/migrations/0011_alter_identifiermodel_device_created_and_more.py +79 -0
  114. edc_identifier/model_mixins.py +1 -1
  115. edc_identifier/models.py +9 -9
  116. edc_identifier/simple_identifier.py +1 -3
  117. edc_identifier/subject_identifier.py +3 -2
  118. edc_lab/migrations/0001_initial.py +29 -29
  119. edc_lab/migrations/0008_auto_20170921_0719.py +3 -3
  120. edc_lab/migrations/0010_auto_20171127_1541.py +15 -15
  121. edc_lab/migrations/0012_auto_20180114_1438.py +3 -3
  122. edc_lab/migrations/0019_auto_20190305_0123.py +43 -127
  123. edc_lab/migrations/0036_alter_aliquot_comment_alter_aliquot_device_created_and_more.py +1139 -0
  124. edc_lab/migrations/0037_alter_historicalorder_order_datetime_and_more.py +31 -0
  125. edc_lab/model_mixins/aliquot/aliquot_identifier_model_mixin.py +2 -2
  126. edc_lab/model_mixins/aliquot/aliquot_model_mixin.py +2 -2
  127. edc_lab/model_mixins/panel_model_mixin.py +18 -7
  128. edc_lab/model_mixins/requisition/crf_with_requisition_model_mixin.py +2 -4
  129. edc_lab/model_mixins/requisition/requisition_model_mixin.py +7 -8
  130. edc_lab/model_mixins/requisition/requisition_verify_model_mixin.py +1 -1
  131. edc_lab/model_mixins/result/result_item_model_mixin.py +4 -4
  132. edc_lab/model_mixins/shipping/manifest_model_mixin.py +4 -5
  133. edc_lab/model_mixins/shipping/verify_model_mixin.py +4 -6
  134. edc_lab/models/box.py +1 -1
  135. edc_lab/models/box_item.py +6 -7
  136. edc_lab/models/manifest/manifest.py +1 -1
  137. edc_lab/models/manifest/manifest_item.py +6 -6
  138. edc_lab/models/manifest/shipper.py +3 -4
  139. edc_lab/models/order.py +6 -4
  140. edc_lab/models/panel.py +4 -4
  141. edc_lab/models/result.py +2 -2
  142. edc_lab/models/result_item.py +2 -2
  143. edc_lab_dashboard/migrations/0001_initial.py +3 -2
  144. edc_lab_dashboard/migrations/0005_alter_edcpermissions_device_created_and_more.py +49 -0
  145. edc_lab_dashboard/views/action_views/receive_view.py +2 -2
  146. edc_lab_dashboard/views/action_views/verify_box_item_view.py +2 -2
  147. edc_lab_results/model_mixins/blood_result_model_mixin.py +7 -7
  148. edc_lab_results/model_mixins/fbg_model_mixin.py +3 -3
  149. edc_lab_results/model_mixins/glucose_model_mixin.py +3 -3
  150. edc_lab_results/model_mixins/hba1c_model_mixin.py +3 -3
  151. edc_label/migrations/0001_initial.py +3 -2
  152. edc_label/migrations/0007_alter_zpllabeltemplates_device_created_and_more.py +49 -0
  153. edc_list_data/list_model_maker.py +2 -2
  154. edc_list_data/load_list_data.py +11 -14
  155. edc_list_data/model_mixins.py +12 -4
  156. edc_list_data/preload_data.py +3 -3
  157. edc_listboard/migrations/0001_initial.py +3 -2
  158. edc_listboard/migrations/0007_alter_listboard_device_created_and_more.py +49 -0
  159. edc_locator/migrations/0001_initial.py +7 -7
  160. edc_locator/migrations/0018_auto_20190305_0123.py +5 -12
  161. edc_locator/migrations/0040_alter_historicalsubjectlocator_action_identifier_and_more.py +187 -0
  162. edc_locator/migrations/0041_alter_historicalsubjectlocator_report_datetime_and_more.py +27 -0
  163. edc_locator/model_mixins/locator_model_mixin.py +2 -2
  164. edc_locator/model_mixins/subject_contact_fields_mixin.py +1 -1
  165. edc_locator/modeladmin_mixins.py +5 -4
  166. edc_ltfu/model_mixins.py +7 -5
  167. edc_metadata/metadata_rules/decorators.py +1 -1
  168. edc_metadata/migrations/0002_auto_20161127_2226.py +5 -5
  169. edc_metadata/migrations/0005_auto_20170112_0602.py +5 -5
  170. edc_metadata/migrations/0011_auto_20190305_0123.py +5 -12
  171. edc_metadata/migrations/0031_alter_crfmetadata_device_created_and_more.py +120 -0
  172. edc_metadata/model_mixins/updates/updates_crf_metadata_model_mixin.py +1 -1
  173. edc_metadata/model_mixins/updates/updates_requisition_metadata_model_mixin.py +1 -1
  174. edc_metadata/models/crf_metadata.py +5 -5
  175. edc_metadata/models/crf_metadata_model_mixin.py +4 -5
  176. edc_metadata/models/requisition_metadata.py +6 -6
  177. edc_metadata/views/refresh_metadata_actions_view.py +3 -3
  178. edc_model/models/address_mixin.py +6 -6
  179. edc_model/models/fields/initials_field.py +2 -1
  180. edc_model/models/historical_records.py +2 -9
  181. edc_model/models/url_model_mixin.py +2 -2
  182. edc_model/validators/date.py +7 -8
  183. edc_model_admin/list_filters/future_date_list_filter.py +3 -3
  184. edc_model_admin/list_filters/past_date_list_filter.py +3 -3
  185. edc_model_admin/mixins/model_admin_protect_pii_mixin.py +4 -5
  186. edc_model_fields/fields/other_charfield.py +2 -2
  187. edc_navbar/migrations/0004_auto_20220825_0451.py +3 -2
  188. edc_navbar/migrations/0009_alter_edcpermissions_device_created_and_more.py +49 -0
  189. edc_notification/migrations/0001_initial.py +3 -3
  190. edc_notification/migrations/0004_auto_20190305_0123.py +3 -6
  191. edc_notification/migrations/0011_alter_notification_device_created_and_more.py +59 -0
  192. edc_notification/models/notification.py +1 -1
  193. edc_notification/notification/notification.py +12 -12
  194. edc_offstudy/migrations/0001_initial.py +4 -4
  195. edc_offstudy/migrations/0002_auto_20180921_0434.py +4 -4
  196. edc_offstudy/migrations/0005_auto_20190305_0123.py +5 -12
  197. edc_offstudy/migrations/0023_alter_historicalsubjectoffstudy_action_identifier_and_more.py +188 -0
  198. edc_offstudy/migrations/0024_alter_historicalsubjectoffstudy_offstudy_datetime_and_more.py +43 -0
  199. edc_offstudy/model_mixins/offstudy_model_mixin.py +3 -2
  200. edc_pdutils/df_exporters/csv_exporter.py +33 -37
  201. edc_pdutils/df_exporters/csv_model_exporter.py +2 -1
  202. edc_pdutils/migrations/0001_initial.py +8 -8
  203. edc_pharmacy/admin/prescription/rx_refill_admin.py +4 -3
  204. edc_pharmacy/admin/reports/stock_availability_admin.py +5 -6
  205. edc_pharmacy/migrations/0001_initial.py +64 -63
  206. edc_pharmacy/migrations/0015_auto_20220913_2139.py +26 -26
  207. edc_pharmacy/migrations/0024_allocation_assignment_containerunits_dispense_and_more.py +81 -86
  208. edc_pharmacy/migrations/0037_remove_historicalstock_confirmed_at_site_by_and_more.py +5 -5
  209. edc_pharmacy/migrations/0039_remove_dispense_registered_subject_and_more.py +7 -8
  210. edc_pharmacy/migrations/0049_remove_stocktransferconfirmation_stock_and_more.py +12 -12
  211. edc_pharmacy/migrations/0050_remove_stocktransferconfirmation2_location_and_more.py +5 -5
  212. edc_pharmacy/migrations/0051_alter_historicalstocktransferconfirmationitem_options_and_more.py +3 -4
  213. edc_pharmacy/migrations/0053_alter_location_managers_alter_historicalstock_lot_and_more.py +3 -3
  214. edc_pharmacy/migrations/0057_scanduplicates.py +3 -3
  215. edc_pharmacy/migrations/0060_alter_container_max_per_subject_and_more.py +13 -15
  216. edc_pharmacy/migrations/0068_stockout.py +2 -3
  217. edc_pharmacy/migrations/0076_historicalstockadjustment_stockadjustment.py +5 -5
  218. edc_pharmacy/migrations/0077_historicalstockadjustment_adjustment_datetime_and_more.py +3 -4
  219. edc_pharmacy/migrations/0081_historicalconfirmation_confirmation.py +8 -8
  220. edc_pharmacy/migrations/0084_confirmationatsiteitem_and_more.py +0 -2
  221. edc_pharmacy/migrations/0089_alter_allocation_allocated_by_and_more.py +3284 -0
  222. edc_pharmacy/migrations/0090_alter_allocation_allocation_datetime_and_more.py +227 -0
  223. edc_pharmacy/model_mixins/study_medication_refill_model_mixin.py +2 -2
  224. edc_pharmacy/models/medication/medication.py +3 -3
  225. edc_pharmacy/models/model_mixins.py +10 -11
  226. edc_pharmacy/models/prescription/rx.py +13 -12
  227. edc_pharmacy/models/prescription/rx_refill.py +0 -1
  228. edc_pharmacy/models/stock/allocation.py +3 -3
  229. edc_pharmacy/models/stock/confirmation.py +3 -3
  230. edc_pharmacy/models/stock/confirmation_at_site.py +3 -2
  231. edc_pharmacy/models/stock/confirmation_at_site_item.py +3 -4
  232. edc_pharmacy/models/stock/dispense.py +5 -6
  233. edc_pharmacy/models/stock/dispense_item.py +2 -2
  234. edc_pharmacy/models/stock/location.py +3 -4
  235. edc_pharmacy/models/stock/lot.py +6 -7
  236. edc_pharmacy/models/stock/order.py +1 -1
  237. edc_pharmacy/models/stock/receive.py +3 -3
  238. edc_pharmacy/models/stock/receive_item.py +4 -4
  239. edc_pharmacy/models/stock/repack_request.py +2 -2
  240. edc_pharmacy/models/stock/stock.py +12 -18
  241. edc_pharmacy/models/stock/stock_adjustment.py +4 -4
  242. edc_pharmacy/models/stock/stock_request.py +2 -2
  243. edc_pharmacy/models/stock/stock_request_item.py +2 -2
  244. edc_pharmacy/models/stock/stock_transfer.py +3 -3
  245. edc_pharmacy/models/stock/stock_transfer_item.py +2 -2
  246. edc_pharmacy/models/stock/storage_bin.py +3 -4
  247. edc_pharmacy/models/stock/storage_bin_item.py +2 -2
  248. edc_pharmacy/models/stock/supplier.py +3 -4
  249. edc_pharmacy/models/storage/box.py +2 -2
  250. edc_pharmacy/models/storage/items/container_model_mixin.py +3 -4
  251. edc_pharmacy/models/storage/items/pill_bottle_model_mixin.py +2 -2
  252. edc_pharmacy/models/storage/items/subject_pill_bottle.py +1 -1
  253. edc_pharmacy/models/storage/room.py +2 -2
  254. edc_pharmacy/models/storage/shelf.py +2 -2
  255. edc_pharmacy/models/storage/utils.py +1 -1
  256. edc_pharmacy/utils/allocate_stock.py +2 -3
  257. edc_pharmacy/utils/confirm_stock.py +2 -3
  258. edc_pharmacy/utils/confirm_stock_at_site.py +3 -4
  259. edc_pharmacy/utils/dispense.py +3 -4
  260. edc_pharmacy/utils/process_repack_request.py +4 -5
  261. edc_pharmacy/utils/stock_request/bulk_create_stock_request_items.py +2 -3
  262. edc_pharmacy/utils/transfer_stock.py +2 -3
  263. edc_pharmacy/views/add_to_storage_bin_view.py +2 -2
  264. edc_pharmacy/views/allocate_to_subject_view.py +2 -2
  265. edc_pharmacy/views/dispense_view.py +2 -2
  266. edc_pharmacy/views/move_to_storage_bin_view.py +2 -3
  267. edc_pharmacy/views/print_labels_view.py +2 -2
  268. edc_protocol/research_protocol_config.py +2 -3
  269. edc_protocol_incident/migrations/0001_initial.py +7 -7
  270. edc_protocol_incident/migrations/0001_squashed_0015_auto_20220927_0401.py +13 -13
  271. edc_protocol_incident/migrations/0005_protocolincident_historicalprotocolincident_and_more.py +7 -7
  272. edc_protocol_incident/migrations/0024_alter_actionsrequired_extra_value_and_more.py +625 -0
  273. edc_protocol_incident/migrations/0025_alter_historicalprotocoldeviationviolation_report_datetime_and_more.py +42 -0
  274. edc_protocol_incident/model_mixins/protocol_deviation_violation_model_mixin.py +18 -11
  275. edc_protocol_incident/model_mixins/protocol_incident_model_mixin.py +26 -11
  276. edc_pylabels/actions.py +3 -5
  277. edc_pylabels/migrations/0002_alter_label_options_label_created_and_more.py +3 -7
  278. edc_pylabels/migrations/0005_labelconfiguration_delete_label_and_more.py +3 -3
  279. edc_pylabels/migrations/0013_alter_labelconfiguration_device_created_and_more.py +49 -0
  280. edc_qareports/migrations/0001_initial.py +4 -5
  281. edc_qareports/migrations/0005_edcpermissions.py +3 -3
  282. edc_qareports/migrations/0006_qareportlog.py +2 -3
  283. edc_qareports/migrations/0019_alter_edcpermissions_device_created_and_more.py +102 -0
  284. edc_qareports/migrations/0020_alter_note_report_datetime_and_more.py +24 -0
  285. edc_qareports/model_mixins/note_model_mixin.py +7 -4
  286. edc_qareports/model_mixins/on_study_missing_values_model_mixin.py +4 -4
  287. edc_qareports/model_mixins/qa_report_model_mixin.py +2 -3
  288. edc_qareports/models/note.py +4 -4
  289. edc_qareports/models/qa_reports_log.py +2 -3
  290. edc_randomization/decorators.py +1 -1
  291. edc_randomization/migrations/0001_initial.py +3 -2
  292. edc_randomization/migrations/0002_historicalrandomizationlist.py +3 -2
  293. edc_randomization/migrations/0009_edcpermissions.py +3 -2
  294. edc_randomization/migrations/0014_alter_edcpermissions_device_created_and_more.py +141 -0
  295. edc_randomization/model_mixins.py +9 -9
  296. edc_randomization/utils.py +2 -2
  297. edc_refusal/migrations/0001_initial.py +4 -4
  298. edc_refusal/migrations/0002_historicalsubjectrefusal.py +4 -4
  299. edc_refusal/migrations/0012_alter_historicalsubjectrefusal_comment_and_more.py +122 -0
  300. edc_refusal/migrations/0013_alter_historicalsubjectrefusal_report_datetime_and_more.py +28 -0
  301. edc_refusal/model_mixins.py +3 -3
  302. edc_registration/migrations/0002_auto_20161127_2226.py +3 -4
  303. edc_registration/migrations/0005_auto_20170111_1809.py +4 -2
  304. edc_registration/migrations/0016_historicalregisteredsubject.py +3 -2
  305. edc_registration/migrations/0017_auto_20190305_0123.py +5 -12
  306. edc_registration/migrations/0033_alter_historicalregisteredsubject_additional_key_and_more.py +302 -0
  307. edc_registration/model_mixins/updates_or_creates_registered_subject_model_mixin.py +2 -3
  308. edc_registration/models/registered_subject.py +27 -26
  309. edc_reportable/age_evaluator.py +4 -2
  310. edc_reportable/formula.py +5 -5
  311. edc_reportable/migrations/0001_initial.py +7 -7
  312. edc_reportable/migrations/0003_referencerangecollection_grade1_and_more.py +3 -3
  313. edc_reportable/migrations/0004_alter_referencerangecollection_grade3_and_more.py +5 -5
  314. edc_reportable/migrations/0006_alter_gradingdata_revision_and_more.py +5 -6
  315. edc_reportable/migrations/0007_alter_gradingdata_age_phrase_and_more.py +509 -0
  316. edc_reportable/models/normal_data.py +4 -5
  317. edc_reportable/models/reference_model_mixins.py +10 -11
  318. edc_reportable/models/reference_range_collection.py +12 -13
  319. edc_reportable/post_migrate_signals.py +1 -1
  320. edc_reportable/utils/convert_units.py +11 -45
  321. edc_reportable/utils/get_normal_data_or_raise.py +2 -2
  322. edc_reportable/utils/load_data.py +4 -4
  323. edc_reportable/utils/update_grading_data.py +5 -5
  324. edc_review_dashboard/migrations/0001_initial.py +3 -2
  325. edc_review_dashboard/migrations/0006_alter_edcpermissions_device_created_and_more.py +49 -0
  326. edc_screening/age_evaluator.py +3 -3
  327. edc_screening/migrations/0001_initial.py +3 -2
  328. edc_screening/migrations/0005_alter_edcpermissions_device_created_and_more.py +49 -0
  329. edc_screening/model_mixins/eligibility_model_mixin.py +3 -4
  330. edc_screening/model_mixins/screening_fields_model_mixin.py +6 -8
  331. edc_search/model_mixins.py +2 -3
  332. edc_search/search_slug.py +9 -8
  333. edc_search/updater.py +2 -2
  334. edc_sites/migrations/0007_edcpermissions.py +3 -2
  335. edc_sites/migrations/0010_alter_edcpermissions_device_created_and_more.py +69 -0
  336. edc_sites/model_mixins/site_model_mixin.py +2 -2
  337. edc_sites/site.py +5 -5
  338. edc_sites/system_checks.py +1 -1
  339. edc_subject_dashboard/migrations/0001_initial.py +3 -2
  340. edc_subject_dashboard/migrations/0005_alter_edcpermissions_device_created_and_more.py +49 -0
  341. edc_subject_dashboard/requisition_report.py +6 -4
  342. edc_subject_dashboard/requisition_verifier.py +6 -6
  343. edc_subject_dashboard/templatetags/edc_subject_dashboard_extras.py +2 -2
  344. edc_subject_dashboard/view_mixins/subject_visit_view_mixin.py +7 -8
  345. edc_subject_dashboard/view_utils/subject_consent_listboard_button.py +3 -2
  346. edc_subject_dashboard/view_utils/timepoint_status_button.py +2 -2
  347. edc_timepoint/model_mixins.py +22 -20
  348. edc_transfer/model_mixins.py +4 -4
  349. edc_transfer/modeladmin_mixins.py +1 -1
  350. edc_unblinding/migrations/0001_initial.py +13 -13
  351. edc_unblinding/migrations/0014_alter_historicalunblindingrequest_action_identifier_and_more.py +291 -0
  352. edc_unblinding/migrations/0015_alter_historicalunblindingrequest_report_datetime_and_more.py +45 -0
  353. edc_unblinding/models/unblinding_request.py +2 -2
  354. edc_unblinding/models/unblinding_review.py +3 -3
  355. edc_utils/age.py +10 -16
  356. edc_visit_schedule/migrations/0001_initial.py +3 -3
  357. edc_visit_schedule/migrations/0002_auto_20190305_0123.py +3 -6
  358. edc_visit_schedule/migrations/0003_historicalvisitschedule_visitschedule.py +5 -4
  359. edc_visit_schedule/migrations/0015_historicalonschedule_offschedule_onschedule.py +10 -10
  360. edc_visit_schedule/migrations/0019_alter_historicalonschedule_device_created_and_more.py +229 -0
  361. edc_visit_schedule/migrations/0020_alter_historicalonschedule_onschedule_datetime_and_more.py +65 -0
  362. edc_visit_schedule/model_mixins/off_schedule_model_mixin.py +5 -4
  363. edc_visit_schedule/model_mixins/on_schedule_model_mixin.py +5 -4
  364. edc_visit_schedule/model_mixins/visit_schedule/visit_code_fields_model_mixin.py +1 -1
  365. edc_visit_schedule/models/subject_schedule_history.py +6 -6
  366. edc_visit_schedule/schedule/visit_collection.py +1 -1
  367. edc_visit_schedule/subject_schedule.py +5 -4
  368. edc_visit_schedule/view_mixins.py +2 -3
  369. edc_visit_schedule/visit/visit.py +3 -2
  370. edc_visit_tracking/migrations/0004_subjectvisit_subjectvisitmissedreasons_extra_value_and_more.py +13 -13
  371. edc_visit_tracking/migrations/0009_alter_historicalsubjectvisit_comments_and_more.py +450 -0
  372. edc_visit_tracking/migrations/0010_alter_historicalsubjectvisit_report_datetime_and_more.py +68 -0
  373. edc_visit_tracking/model_mixins/base/visit_methods_model_mixin.py +3 -3
  374. edc_visit_tracking/model_mixins/crfs/visit_tracking_crf_model_mixin.py +2 -2
  375. edc_visit_tracking/model_mixins/requisitions/visit_tracking_requisition_model_mixin.py +2 -2
  376. edc_visit_tracking/model_mixins/subject_visit_missed_model_mixin.py +2 -2
  377. edc_visit_tracking/model_mixins/visit_model_mixin/caretaker_fields_mixin.py +2 -3
  378. edc_visit_tracking/model_mixins/visit_model_mixin/previous_visit_model_mixin.py +1 -1
  379. edc_visit_tracking/model_mixins/visit_model_mixin/visit_model_fields_mixin.py +8 -11
  380. edc_visit_tracking/model_mixins/visit_model_mixin/visit_model_mixin.py +1 -1
  381. edc_visit_tracking/models/signals.py +1 -1
  382. edc_visit_tracking/models/subject_visit.py +1 -1
  383. edc_vitals/calculators/bmi.py +7 -5
  384. edc_vitals/form_validators/blood_pressure_form_validator_mixin.py +3 -1
  385. edc_vitals/utils.py +1 -1
  386. {clinicedc-2.0.5.dist-info → clinicedc-2.0.7.dist-info}/WHEEL +0 -0
  387. {clinicedc-2.0.5.dist-info → clinicedc-2.0.7.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,69 @@
1
+ # Generated by Django 5.2.6 on 2025-09-17 16:53
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ("edc_sites", "0009_alter_edcpermissions_revision"),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterField(
14
+ model_name="edcpermissions",
15
+ name="device_created",
16
+ field=models.CharField(
17
+ blank=True, default="", max_length=10, verbose_name="Device created"
18
+ ),
19
+ ),
20
+ migrations.AlterField(
21
+ model_name="edcpermissions",
22
+ name="device_modified",
23
+ field=models.CharField(
24
+ blank=True, default="", max_length=10, verbose_name="Device modified"
25
+ ),
26
+ ),
27
+ migrations.AlterField(
28
+ model_name="edcpermissions",
29
+ name="locale_created",
30
+ field=models.CharField(
31
+ blank=True,
32
+ default="",
33
+ help_text="Auto-updated by Modeladmin",
34
+ max_length=10,
35
+ verbose_name="Locale created",
36
+ ),
37
+ ),
38
+ migrations.AlterField(
39
+ model_name="edcpermissions",
40
+ name="locale_modified",
41
+ field=models.CharField(
42
+ blank=True,
43
+ default="",
44
+ help_text="Auto-updated by Modeladmin",
45
+ max_length=10,
46
+ verbose_name="Locale modified",
47
+ ),
48
+ ),
49
+ migrations.AlterField(
50
+ model_name="siteprofile",
51
+ name="country",
52
+ field=models.CharField(default="", max_length=250),
53
+ ),
54
+ migrations.AlterField(
55
+ model_name="siteprofile",
56
+ name="country_code",
57
+ field=models.CharField(default="", max_length=15),
58
+ ),
59
+ migrations.AlterField(
60
+ model_name="siteprofile",
61
+ name="languages",
62
+ field=models.TextField(default=""),
63
+ ),
64
+ migrations.AlterField(
65
+ model_name="siteprofile",
66
+ name="title",
67
+ field=models.CharField(default="", max_length=250),
68
+ ),
69
+ ]
@@ -28,7 +28,7 @@ class SiteModelMixin(models.Model):
28
28
  self.update_site_on_save(*args, **kwargs)
29
29
  super().save(*args, **kwargs)
30
30
 
31
- def update_site_on_save(self, *args, **kwargs) -> None:
31
+ def update_site_on_save(self, *args, **kwargs) -> None: # noqa: ARG002
32
32
  if not self.id:
33
33
  if not self.site_id and not self.site:
34
34
  self.site = self.get_site_on_create()
@@ -59,7 +59,7 @@ class SiteModelMixin(models.Model):
59
59
  "Exception raised when trying manager method `get_current()`. "
60
60
  f"Sites registered with `sites` global are {site_ids}. "
61
61
  f"settings.SITE_ID={settings.SITE_ID}. Got {e}."
62
- )
62
+ ) from e
63
63
  return site_obj
64
64
 
65
65
  def validate_site_against_current(self) -> None:
edc_sites/site.py CHANGED
@@ -160,13 +160,13 @@ class Sites:
160
160
  single_site = dataclasses.replace(single_site, domain=domain)
161
161
 
162
162
  if single_site.site_id in self._registry:
163
- raise AlreadyRegistered(f"Site already registered. Got `{single_site}`.") # noqa: TRY003
163
+ raise AlreadyRegistered(f"Site already registered. Got `{single_site}`.")
164
164
  if single_site.name in [s.name for s in self._registry.values()]:
165
- raise AlreadyRegisteredName( # noqa: TRY003
165
+ raise AlreadyRegisteredName(
166
166
  f"Site with this name is already registered. Got `{single_site}`."
167
167
  )
168
168
  if single_site.domain in [s.domain for s in self._registry.values()]:
169
- raise AlreadyRegisteredDomain( # noqa: TRY003
169
+ raise AlreadyRegisteredDomain(
170
170
  f"Site with this domain is already registered. Got `{single_site}`."
171
171
  )
172
172
  self._registry.update({single_site.site_id: single_site})
@@ -187,7 +187,7 @@ class Sites:
187
187
  msg = "In fact, no sites have been registered!"
188
188
  else:
189
189
  msg = f"Expected one of {[s.site_id for s in self.all(aslist=True)]}."
190
- raise SiteNotRegistered( # noqa: TRY003
190
+ raise SiteNotRegistered(
191
191
  f"Site not registered. {msg} See {self!r}. Got `{site_id}`."
192
192
  )
193
193
  return self._registry.get(site_id)
@@ -196,7 +196,7 @@ class Sites:
196
196
  for single_site in self._registry.values():
197
197
  if getattr(single_site, attrname) == value:
198
198
  return single_site
199
- raise SiteDoesNotExist(f"No site exists with `{attrname}`==`{value}`.") # noqa: TRY003
199
+ raise SiteDoesNotExist(f"No site exists with `{attrname}`==`{value}`.")
200
200
 
201
201
  def all(self, aslist: bool | None = None) -> dict[int, SingleSite] | list[SingleSite]:
202
202
  if aslist:
@@ -10,7 +10,7 @@ from edc_sites.site import sites as site_sites
10
10
  from edc_sites.utils import get_site_model_cls
11
11
 
12
12
 
13
- def sites_check(app_configs, **kwargs): # noqa
13
+ def sites_check(app_configs, **kwargs):
14
14
  errors = []
15
15
  if "migrate" not in sys.argv and "makemigrations" not in sys.argv:
16
16
  try:
@@ -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_subject_dashboard", "0004_alter_edcpermissions_revision"),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterField(
14
+ model_name="edcpermissions",
15
+ name="device_created",
16
+ field=models.CharField(
17
+ blank=True, default="", max_length=10, verbose_name="Device created"
18
+ ),
19
+ ),
20
+ migrations.AlterField(
21
+ model_name="edcpermissions",
22
+ name="device_modified",
23
+ field=models.CharField(
24
+ blank=True, default="", max_length=10, verbose_name="Device modified"
25
+ ),
26
+ ),
27
+ migrations.AlterField(
28
+ model_name="edcpermissions",
29
+ name="locale_created",
30
+ field=models.CharField(
31
+ blank=True,
32
+ default="",
33
+ help_text="Auto-updated by Modeladmin",
34
+ max_length=10,
35
+ verbose_name="Locale created",
36
+ ),
37
+ ),
38
+ migrations.AlterField(
39
+ model_name="edcpermissions",
40
+ name="locale_modified",
41
+ field=models.CharField(
42
+ blank=True,
43
+ default="",
44
+ help_text="Auto-updated by Modeladmin",
45
+ max_length=10,
46
+ verbose_name="Locale modified",
47
+ ),
48
+ ),
49
+ ]
@@ -1,6 +1,7 @@
1
1
  from tempfile import mkdtemp
2
2
 
3
3
  from django.contrib import messages
4
+ from django.utils import timezone
4
5
  from reportlab.graphics.barcode import code39
5
6
  from reportlab.lib import colors
6
7
  from reportlab.lib.units import cm, mm
@@ -11,7 +12,6 @@ from edc_identifier.utils import convert_to_human_readable
11
12
  from edc_lab.model_mixins import RequisitionModelMixin
12
13
  from edc_lab.models.manifest.shipper import Shipper
13
14
  from edc_pdf_reports import Report
14
- from edc_utils import get_utcnow
15
15
 
16
16
 
17
17
  class RequisitionReport(Report):
@@ -33,7 +33,7 @@ class RequisitionReport(Report):
33
33
  self.consignee = consignee
34
34
  self.contact_name = f"{self.user.first_name} {self.user.last_name}"
35
35
  self.image_folder = mkdtemp()
36
- self.timestamp = get_utcnow().strftime("%Y%m%d%H%M%S")
36
+ self.timestamp = timezone.now().strftime("%Y%m%d%H%M%S")
37
37
  self.report_filename = f"requisition_{self.timestamp}.pdf"
38
38
 
39
39
  @property
@@ -60,7 +60,9 @@ class RequisitionReport(Report):
60
60
  Paragraph("REFERENCE", self.styles["line_label"]),
61
61
  ],
62
62
  [
63
- Paragraph(get_utcnow().strftime("%Y-%m-%d"), self.styles["line_data_largest"]),
63
+ Paragraph(
64
+ timezone.now().strftime("%Y-%m-%d"), self.styles["line_data_largest"]
65
+ ),
64
66
  Paragraph(
65
67
  convert_to_human_readable(self.timestamp),
66
68
  self.styles["line_data_largest"],
@@ -173,7 +175,7 @@ class RequisitionReport(Report):
173
175
  Paragraph(self.contact_name, self.styles["line_data_large"]),
174
176
  "",
175
177
  Paragraph(
176
- get_utcnow().strftime("%Y-%m-%d %H:%M"),
178
+ timezone.now().strftime("%Y-%m-%d %H:%M"),
177
179
  self.styles["line_data_large"],
178
180
  ),
179
181
  ],
@@ -1,10 +1,12 @@
1
+ import contextlib
2
+
1
3
  from django.core.exceptions import ObjectDoesNotExist
4
+ from django.utils import timezone
2
5
 
3
6
  from edc_appointment.models import Appointment
4
7
  from edc_constants.constants import NO, YES
5
8
  from edc_lab.constants import TUBE
6
9
  from edc_lab.model_mixins import RequisitionModelMixin
7
- from edc_utils import get_utcnow
8
10
 
9
11
 
10
12
  class RequisitionVerifier:
@@ -22,12 +24,12 @@ class RequisitionVerifier:
22
24
  if self.requisition and self.requisition.is_drawn != NO:
23
25
  # verification fields
24
26
  self.requisition.clinic_verified = YES
25
- self.requisition.clinic_verified_datetime = get_utcnow()
27
+ self.requisition.clinic_verified_datetime = timezone.now()
26
28
  # other fields for label printing
27
29
  self.requisition.is_drawn = self.requisition.is_drawn or YES
28
30
  self.requisition.item_count = self.requisition.item_count or 1
29
31
  self.requisition.item_type = self.requisition.item_type or TUBE
30
- self.requisition.drawn_datetime = self.requisition.drawn_datetime or get_utcnow()
32
+ self.requisition.drawn_datetime = self.requisition.drawn_datetime or timezone.now()
31
33
  self.requisition.save()
32
34
  self.verified = self.requisition.clinic_verified
33
35
 
@@ -43,12 +45,10 @@ class RequisitionVerifier:
43
45
  def requisition(self):
44
46
  """Returns a requisition model instance."""
45
47
  if not self._requisition:
46
- try:
48
+ with contextlib.suppress(ObjectDoesNotExist):
47
49
  self._requisition = self.requisition_model_cls.objects.get(
48
50
  requisition_identifier=self.requisition_identifier.strip()
49
51
  )
50
- except ObjectDoesNotExist:
51
- pass
52
52
  return self._requisition
53
53
 
54
54
  @property
@@ -8,6 +8,7 @@ from django import template
8
8
  from django.apps import apps as django_apps
9
9
  from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
10
10
  from django.urls import reverse
11
+ from django.utils import timezone
11
12
 
12
13
  from edc_appointment.constants import (
13
14
  CANCELLED_APPT,
@@ -26,7 +27,6 @@ from edc_appointment.view_utils import AppointmentButton
26
27
  from edc_auth.constants import AUDITOR_ROLE
27
28
  from edc_metadata import KEYED, REQUIRED
28
29
  from edc_metadata.metadata_helper import MetadataHelper
29
- from edc_utils import get_utcnow
30
30
  from edc_view_utils import PrnButton, render_history_and_query_buttons
31
31
  from edc_visit_tracking.view_utils import RelatedVisitButton
32
32
 
@@ -171,7 +171,7 @@ def render_crf_totals(appointment: Appointment = None) -> dict[str, bool | int]:
171
171
  skipped = True
172
172
  elif (
173
173
  appointment.appt_status == NEW_APPT
174
- and appointment.appt_datetime.date() < get_utcnow().date()
174
+ and appointment.appt_datetime.date() < timezone.now().date()
175
175
  ):
176
176
  overdue = True
177
177
  else:
@@ -1,10 +1,11 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import contextlib
3
4
  from typing import TYPE_CHECKING, Any
4
5
 
5
6
  from django.core.exceptions import ObjectDoesNotExist
7
+ from django.utils import timezone
6
8
 
7
- from edc_utils import get_utcnow
8
9
  from edc_visit_schedule.models import VisitSchedule
9
10
 
10
11
  if TYPE_CHECKING:
@@ -46,8 +47,8 @@ class SubjectVisitViewMixin:
46
47
  self._related_visit = self.appointment.related_visit
47
48
  except AttributeError as e:
48
49
  raise SubjectVisitViewMixinError(
49
- "Visit model must have a OneToOne relation to appointment. " f"Got {e}"
50
- )
50
+ f"Visit model must have a OneToOne relation to appointment. Got {e}"
51
+ ) from e
51
52
  return self._related_visit
52
53
 
53
54
  def get_visit_schedule(self) -> VisitSchedule | None:
@@ -60,10 +61,8 @@ class SubjectVisitViewMixin:
60
61
  schedule_name=self.appointment.schedule_name,
61
62
  visit_code=self.appointment.visit_code,
62
63
  )
63
- try:
64
+ with contextlib.suppress(ObjectDoesNotExist):
64
65
  visit_schedule = VisitSchedule.objects.get(**opts)
65
- except ObjectDoesNotExist:
66
- pass
67
66
  return visit_schedule
68
67
 
69
68
  @property
@@ -76,7 +75,7 @@ class SubjectVisitViewMixin:
76
75
  try:
77
76
  self._report_datetime = self.appointment.appt_datetime
78
77
  except AttributeError:
79
- self._report_datetime = get_utcnow()
78
+ self._report_datetime = timezone.now()
80
79
  return self._report_datetime
81
80
 
82
81
  def has_appointment_attr_or_raise(self) -> None:
@@ -89,5 +88,5 @@ class SubjectVisitViewMixin:
89
88
  if "appointment" in str(e):
90
89
  raise SubjectVisitViewMixinError(
91
90
  f"Mixin must be declared together with AppointmentViewMixin. Got {e}"
92
- )
91
+ ) from e
93
92
  raise
@@ -5,10 +5,11 @@ from dataclasses import dataclass, field
5
5
  from typing import TYPE_CHECKING, TypeVar
6
6
  from uuid import UUID
7
7
 
8
+ from django.utils import timezone
9
+
8
10
  from edc_consent import site_consents
9
11
  from edc_pdutils.site import Site
10
12
  from edc_protocol.research_protocol_config import ResearchProtocolConfig
11
- from edc_utils import get_utcnow
12
13
  from edc_view_utils import ModelButton
13
14
 
14
15
  if TYPE_CHECKING:
@@ -42,7 +43,7 @@ class SubjectConsentListboardButton(ModelButton):
42
43
 
43
44
  def __post_init__(self):
44
45
  cdef = site_consents.get_consent_definition(
45
- report_datetime=get_utcnow(),
46
+ report_datetime=timezone.now(),
46
47
  screening_model=self.screening_obj._meta.label_lower,
47
48
  )
48
49
  self.model_cls = cdef.model_cls
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  from dataclasses import dataclass, field
4
4
  from typing import TYPE_CHECKING, TypeVar
5
5
 
6
+ from django.utils import timezone
6
7
  from django.utils.translation import gettext as _
7
8
 
8
9
  from edc_appointment.constants import (
@@ -13,7 +14,6 @@ from edc_appointment.constants import (
13
14
  SKIPPED_APPT,
14
15
  )
15
16
  from edc_appointment.view_utils import AppointmentButton
16
- from edc_utils import get_utcnow
17
17
 
18
18
  if TYPE_CHECKING:
19
19
  from edc_visit_tracking.model_mixins import VisitModelMixin
@@ -79,7 +79,7 @@ class TimepointStatusButton(AppointmentButton):
79
79
  elif self.model_obj.appt_status == INCOMPLETE_APPT:
80
80
  color = self.colors[INCOMPLETE] # default / grey
81
81
  elif self.model_obj.appt_status == NEW_APPT:
82
- if self.model_obj.appt_datetime <= get_utcnow():
82
+ if self.model_obj.appt_datetime <= timezone.now():
83
83
  color = self.colors[NEW_LATE] # warning / orange
84
84
  else:
85
85
  color = self.colors[NEW]
@@ -1,8 +1,7 @@
1
1
  from django.apps import apps as django_apps
2
2
  from django.core.exceptions import ImproperlyConfigured
3
3
  from django.db import models
4
-
5
- from edc_utils import get_utcnow
4
+ from django.utils import timezone
6
5
 
7
6
  from .choices import TIMEPOINT_STATUS
8
7
  from .constants import CLOSED_TIMEPOINT, FEEDBACK, OPEN_TIMEPOINT
@@ -12,10 +11,17 @@ from .timepoint_lookup import TimepointLookup
12
11
  from .utils import get_enable_timepoint_checks
13
12
 
14
13
 
15
- class UnableToCloseTimepoint(Exception):
14
+ class UnableToCloseTimepoint(Exception): # noqa: N818
16
15
  pass
17
16
 
18
17
 
18
+ MODEL_NOT_REGISTERED = (
19
+ "Model not registered. Model '{label_lower}' is not registered "
20
+ "in AppConfig as a timepoint. "
21
+ "See AppConfig for 'edc_timepoint'."
22
+ )
23
+
24
+
19
25
  class TimepointLookupModelMixin(models.Model):
20
26
  """Makes a model lookup the timepoint model instance on `save`
21
27
  and check if it is a closed before allowing a create or update.
@@ -59,15 +65,14 @@ class TimepointModelMixin(models.Model):
59
65
  timepoint_closed_datetime = models.DateTimeField(null=True, editable=False)
60
66
 
61
67
  def save(self, *args, **kwargs):
62
- if self.enabled_as_timepoint:
63
- if (
64
- kwargs.get("update_fields") != ["timepoint_status"]
65
- and kwargs.get("update_fields")
66
- != ["timepoint_opened_datetime", "timepoint_status"]
67
- and kwargs.get("update_fields")
68
- != ["timepoint_closed_datetime", "timepoint_status"]
69
- ):
70
- self.timepoint_open_or_raise()
68
+ if self.enabled_as_timepoint and (
69
+ kwargs.get("update_fields") != ["timepoint_status"]
70
+ and kwargs.get("update_fields")
71
+ != ["timepoint_opened_datetime", "timepoint_status"]
72
+ and kwargs.get("update_fields")
73
+ != ["timepoint_closed_datetime", "timepoint_status"]
74
+ ):
75
+ self.timepoint_open_or_raise()
71
76
  super().save(*args, **kwargs)
72
77
 
73
78
  def update_timepoint(self):
@@ -95,12 +100,10 @@ class TimepointModelMixin(models.Model):
95
100
  app_config = django_apps.get_app_config("edc_timepoint")
96
101
  try:
97
102
  timepoint = app_config.timepoints.get(self._meta.label_lower)
98
- except KeyError:
103
+ except KeyError as e:
99
104
  raise TimepointConfigError(
100
- f"Model '{self._meta.label_lower}' is not registered "
101
- f"in AppConfig as a timepoint. "
102
- f"See AppConfig for 'edc_timepoint'."
103
- )
105
+ MODEL_NOT_REGISTERED.format(label_lower=self._meta.label_lower)
106
+ ) from e
104
107
  if getattr(self, timepoint.status_field) != timepoint.closed_status:
105
108
  self.timepoint_status = OPEN_TIMEPOINT
106
109
  self.timepoint_closed_datetime = None
@@ -122,7 +125,7 @@ class TimepointModelMixin(models.Model):
122
125
  status = getattr(self, timepoint.status_field)
123
126
  if status == timepoint.closed_status:
124
127
  self.timepoint_status = CLOSED_TIMEPOINT
125
- self.timepoint_closed_datetime = get_utcnow()
128
+ self.timepoint_closed_datetime = timezone.now()
126
129
  self.save(update_fields=["timepoint_status"])
127
130
  else:
128
131
  raise UnableToCloseTimepoint(
@@ -146,8 +149,7 @@ class TimepointModelMixin(models.Model):
146
149
  return '<span style="color:red;">Closed</span>'
147
150
  if self.timepoint_status == FEEDBACK:
148
151
  return '<span style="color:orange;">Feedback</span>'
149
-
150
- # timepoint.allow_tags = True
152
+ return None
151
153
 
152
154
  class Meta:
153
155
  abstract = True
@@ -1,5 +1,6 @@
1
1
  from django.conf import settings
2
2
  from django.db import models
3
+ from django.utils import timezone
3
4
  from django_crypto_fields.fields import EncryptedTextField
4
5
 
5
6
  from edc_action_item.models import ActionModelMixin
@@ -8,7 +9,6 @@ from edc_identifier.model_mixins import UniqueSubjectIdentifierFieldMixin
8
9
  from edc_model import models as edc_models
9
10
  from edc_sites.model_mixins import SiteModelMixin
10
11
  from edc_utils import convert_php_dateformat
11
- from edc_utils.date import get_utcnow
12
12
 
13
13
  from .choices import TRANSFER_INITIATORS
14
14
  from .constants import SUBJECT_TRANSFER_ACTION
@@ -23,10 +23,10 @@ class SubjectTransferModelMixin(
23
23
  action_name = SUBJECT_TRANSFER_ACTION
24
24
 
25
25
  report_datetime = models.DateTimeField(
26
- verbose_name="Report Date and Time", default=get_utcnow
26
+ verbose_name="Report Date and Time", default=timezone.now
27
27
  )
28
28
 
29
- transfer_date = models.DateField(verbose_name="Transfer date", default=get_utcnow)
29
+ transfer_date = models.DateField(verbose_name="Transfer date", default=timezone.now)
30
30
 
31
31
  initiated_by = models.CharField(
32
32
  verbose_name="Who initiated the transfer request",
@@ -53,7 +53,7 @@ class SubjectTransferModelMixin(
53
53
  )
54
54
 
55
55
  may_contact = models.CharField(
56
- verbose_name=("Is the participant willing to be contacted at the end of the study?"),
56
+ verbose_name="Is the participant willing to be contacted at the end of the study?",
57
57
  max_length=15,
58
58
  choices=YES_NO,
59
59
  )
@@ -30,7 +30,7 @@ class SubjectTransferModelAdminMixin:
30
30
 
31
31
  filter_horizontal = ("transfer_reason",)
32
32
 
33
- radio_fields = {
33
+ radio_fields = { # noqa: RUF012
34
34
  "initiated_by": admin.VERTICAL,
35
35
  "may_return": admin.VERTICAL,
36
36
  "may_contact": admin.VERTICAL,
@@ -17,7 +17,7 @@ from django.db import migrations, models
17
17
 
18
18
  import edc_identifier.managers
19
19
  import edc_sites.models
20
- import edc_utils.date
20
+ import django.utils.timezone
21
21
 
22
22
 
23
23
  class Migration(migrations.Migration):
@@ -81,14 +81,14 @@ class Migration(migrations.Migration):
81
81
  "created",
82
82
  models.DateTimeField(
83
83
  blank=True,
84
- default=django_audit_fields.models.audit_model_mixin.utcnow,
84
+ default=django.utils.timezone.now,
85
85
  ),
86
86
  ),
87
87
  (
88
88
  "modified",
89
89
  models.DateTimeField(
90
90
  blank=True,
91
- default=django_audit_fields.models.audit_model_mixin.utcnow,
91
+ default=django.utils.timezone.now,
92
92
  ),
93
93
  ),
94
94
  (
@@ -163,7 +163,7 @@ class Migration(migrations.Migration):
163
163
  (
164
164
  "report_datetime",
165
165
  models.DateTimeField(
166
- default=edc_utils.date.get_utcnow,
166
+ default=django.utils.timezone.now,
167
167
  verbose_name="Report Date and Time",
168
168
  ),
169
169
  ),
@@ -257,14 +257,14 @@ class Migration(migrations.Migration):
257
257
  "created",
258
258
  models.DateTimeField(
259
259
  blank=True,
260
- default=django_audit_fields.models.audit_model_mixin.utcnow,
260
+ default=django.utils.timezone.now,
261
261
  ),
262
262
  ),
263
263
  (
264
264
  "modified",
265
265
  models.DateTimeField(
266
266
  blank=True,
267
- default=django_audit_fields.models.audit_model_mixin.utcnow,
267
+ default=django.utils.timezone.now,
268
268
  ),
269
269
  ),
270
270
  (
@@ -339,7 +339,7 @@ class Migration(migrations.Migration):
339
339
  (
340
340
  "report_datetime",
341
341
  models.DateTimeField(
342
- default=edc_utils.date.get_utcnow,
342
+ default=django.utils.timezone.now,
343
343
  verbose_name="Report Date and Time",
344
344
  ),
345
345
  ),
@@ -452,14 +452,14 @@ class Migration(migrations.Migration):
452
452
  "created",
453
453
  models.DateTimeField(
454
454
  blank=True,
455
- default=django_audit_fields.models.audit_model_mixin.utcnow,
455
+ default=django.utils.timezone.now,
456
456
  ),
457
457
  ),
458
458
  (
459
459
  "modified",
460
460
  models.DateTimeField(
461
461
  blank=True,
462
- default=django_audit_fields.models.audit_model_mixin.utcnow,
462
+ default=django.utils.timezone.now,
463
463
  ),
464
464
  ),
465
465
  (
@@ -542,7 +542,7 @@ class Migration(migrations.Migration):
542
542
  (
543
543
  "report_datetime",
544
544
  models.DateTimeField(
545
- default=edc_utils.date.get_utcnow,
545
+ default=django.utils.timezone.now,
546
546
  verbose_name="Report Date and Time",
547
547
  ),
548
548
  ),
@@ -661,14 +661,14 @@ class Migration(migrations.Migration):
661
661
  "created",
662
662
  models.DateTimeField(
663
663
  blank=True,
664
- default=django_audit_fields.models.audit_model_mixin.utcnow,
664
+ default=django.utils.timezone.now,
665
665
  ),
666
666
  ),
667
667
  (
668
668
  "modified",
669
669
  models.DateTimeField(
670
670
  blank=True,
671
- default=django_audit_fields.models.audit_model_mixin.utcnow,
671
+ default=django.utils.timezone.now,
672
672
  ),
673
673
  ),
674
674
  (
@@ -751,7 +751,7 @@ class Migration(migrations.Migration):
751
751
  (
752
752
  "report_datetime",
753
753
  models.DateTimeField(
754
- default=edc_utils.date.get_utcnow,
754
+ default=django.utils.timezone.now,
755
755
  verbose_name="Report Date and Time",
756
756
  ),
757
757
  ),