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
@@ -20,7 +20,6 @@ if TYPE_CHECKING:
20
20
 
21
21
 
22
22
  class ReferenceRangeCollection(BaseUuidModel):
23
-
24
23
  name = models.CharField(max_length=50, unique=True)
25
24
 
26
25
  grade1 = models.BooleanField(default=False)
@@ -60,13 +59,13 @@ class ReferenceRangeCollection(BaseUuidModel):
60
59
 
61
60
  def get_grade(
62
61
  self,
63
- value: float | int = None,
64
- label: str = None,
65
- units: str = None,
62
+ value: float | int | None = None,
63
+ label: str | None = None,
64
+ units: str | None = None,
66
65
  subject_identifier: str | None = None,
67
- report_datetime: datetime = None,
68
- gender: str = None,
69
- dob: date = None,
66
+ report_datetime: datetime | None = None,
67
+ gender: str | None = None,
68
+ dob: date | None = None,
70
69
  age_units: str | None = None,
71
70
  site: Site | None = None,
72
71
  ) -> tuple[GradingData | None, str | None]:
@@ -89,13 +88,13 @@ class ReferenceRangeCollection(BaseUuidModel):
89
88
 
90
89
  def is_normal(
91
90
  self,
92
- value: float | int = None,
93
- label: str = None,
94
- units: str = None,
91
+ value: float | int | None = None,
92
+ label: str | None = None,
93
+ units: str | None = None,
95
94
  subject_identifier: str | None = None,
96
- report_datetime: datetime = None,
97
- gender: str = None,
98
- dob: date = None,
95
+ report_datetime: datetime | None = None,
96
+ gender: str | None = None,
97
+ dob: date | None = None,
99
98
  age_units: str | None = None,
100
99
  site: Site | None = None,
101
100
  ) -> tuple[bool, NormalData]:
@@ -19,7 +19,7 @@ def load_mw():
19
19
  model_cls.objects.get_or_create(label=label, mw=mw)
20
20
 
21
21
 
22
- def post_migrate_load_reference_ranges(sender=None, **kwargs): # noqa
22
+ def post_migrate_load_reference_ranges(sender=None, **kwargs):
23
23
  sys.stdout.write(style.MIGRATE_HEADING("Loading reference ranges (reportables):\n"))
24
24
  load_mw()
25
25
  load_all_reference_ranges()
@@ -20,18 +20,16 @@ __all__ = ["convert_units"]
20
20
  def get_mw(label):
21
21
  try:
22
22
  molecular_weight = molecular_weight_model_cls().objects.get(label=label)
23
- except ObjectDoesNotExist:
23
+ except ObjectDoesNotExist as e:
24
24
  raise ConversionNotHandled(
25
25
  f"Conversion not handled. Molecular weight not found for {label}."
26
- )
26
+ ) from e
27
27
  else:
28
28
  mw = molecular_weight.mw
29
29
  return mw
30
30
 
31
31
 
32
- def micromoles_per_liter_to(
33
- *, label: str = None, value: float | int = None, units_to: str = None
34
- ) -> dict:
32
+ def micromoles_per_liter_to(*, label: str, value: float | int, units_to: str) -> dict:
35
33
  if units_to == MICROMOLES_PER_LITER:
36
34
  return {MICROMOLES_PER_LITER: float(value)}
37
35
  if units_to == MILLIMOLES_PER_LITER:
@@ -44,8 +42,8 @@ def micromoles_per_liter_to(
44
42
 
45
43
 
46
44
  def milligrams_per_deciliter_to(
47
- *, label: str = None, value: float | int = None, units_to: str = None
48
- ) -> dict[str:float]:
45
+ *, label: str, value: float | int, units_to: str
46
+ ) -> dict[str, float]:
49
47
  if units_to == MILLIGRAMS_PER_DECILITER:
50
48
  return {MILLIGRAMS_PER_DECILITER: float(value)}
51
49
  if units_to == MILLIMOLES_PER_LITER:
@@ -63,10 +61,10 @@ class UnitsConverter:
63
61
  def __init__(
64
62
  self,
65
63
  *,
66
- label: str = None,
67
- value: int | float | None = None,
68
- units_from: str | None = None,
69
- units_to: str | None = None,
64
+ label: str,
65
+ value: int | float,
66
+ units_from: str,
67
+ units_to: str,
70
68
  places: int | None = None,
71
69
  ):
72
70
  self.label = label
@@ -97,7 +95,7 @@ class UnitsConverter:
97
95
  f"Conversion not handled. Tried {self.label} from {self.units_from} "
98
96
  f"to {self.units_to}. "
99
97
  f"Got {e} when rounding {converted_value} to {self.places} places."
100
- )
98
+ ) from e
101
99
  return converted_value
102
100
 
103
101
  def from_milligrams_per_deciliter(self) -> float | int:
@@ -106,14 +104,6 @@ class UnitsConverter:
106
104
  label=self.label, value=float(self.value), units_to=self.units_to
107
105
  )[self.units_to]
108
106
  return self.value
109
- # converted_value = None
110
- # if self.units_to == MILLIMOLES_PER_LITER:
111
- # converted_value = (float(self.value) * 10.00) / self.get_mw()
112
- # elif self.units_to == MICROMOLES_PER_LITER:
113
- # converted_value = (float(self.value) * 10.00**3) / self.get_mw()
114
- # elif self.units_to == GRAMS_PER_LITER:
115
- # converted_value = float(self.value) / 100.00
116
- # return converted_value
117
107
 
118
108
  def from_grams_per_liter(self) -> float | int:
119
109
  if self.units_to != GRAMS_PER_LITER:
@@ -123,14 +113,6 @@ class UnitsConverter:
123
113
  units_to=self.units_to,
124
114
  )[self.units_to]
125
115
  return self.value
126
- # converted_value = None
127
- # if self.units_to == MILLIMOLES_PER_LITER:
128
- # converted_value = (self.value * 1000.00) / self.get_mw()
129
- # elif self.units_to == MICROMOLES_PER_LITER:
130
- # converted_value = (self.value * 10.00**6) / self.get_mw()
131
- # elif self.units_to == MILLIGRAMS_PER_DECILITER:
132
- # converted_value = float(self.value) * 100.00
133
- # return converted_value
134
116
 
135
117
  def from_millimoles_per_liter(self) -> float | int:
136
118
  if self.units_to != MILLIMOLES_PER_LITER:
@@ -138,14 +120,6 @@ class UnitsConverter:
138
120
  label=self.label, value=self.value / 1000, units_to=self.units_to
139
121
  )[self.units_to]
140
122
  return self.value
141
- # converted_value = None
142
- # if self.units_to == MICROMOLES_PER_LITER:
143
- # converted_value = self.value * 1000.00
144
- # elif self.units_to == GRAMS_PER_LITER:
145
- # converted_value = (self.value * self.get_mw()) / 1000.00
146
- # elif self.units_to == MILLIGRAMS_PER_DECILITER:
147
- # converted_value = (self.value * self.get_mw()) / 10.00
148
- # return converted_value
149
123
 
150
124
  def from_micromoles_per_liter(self):
151
125
  if self.units_to != MICROMOLES_PER_LITER:
@@ -153,14 +127,6 @@ class UnitsConverter:
153
127
  label=self.label, value=self.value, units_to=self.units_to
154
128
  )[self.units_to]
155
129
  return self.value
156
- # converted_value = None
157
- # if self.units_to == MILLIMOLES_PER_LITER:
158
- # converted_value = self.value / 1000.00
159
- # elif self.units_to == GRAMS_PER_LITER:
160
- # converted_value = (self.value * self.get_mw()) / 10**6
161
- # elif self.units_to == MILLIGRAMS_PER_DECILITER:
162
- # converted_value = (self.value * self.get_mw()) / 10**4
163
- # return converted_value
164
130
 
165
131
  def get_converted_value(self) -> int | float:
166
132
  converted_value = None
@@ -182,7 +148,7 @@ class UnitsConverter:
182
148
 
183
149
  def convert_units(
184
150
  *,
185
- label: str = None,
151
+ label: str | None = None,
186
152
  value: int | float | None = None,
187
153
  units_from: str | None = None,
188
154
  units_to: str | None = None,
@@ -5,10 +5,10 @@ from typing import TYPE_CHECKING
5
5
 
6
6
  from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
7
7
  from django.db.models import Q
8
+ from django.utils import timezone
8
9
 
9
10
  from edc_model_to_dataframe.constants import SYSTEM_COLUMNS
10
11
  from edc_utils import age as get_age
11
- from edc_utils import get_utcnow
12
12
 
13
13
  from ..exceptions import NotEvaluated
14
14
  from .convert_units import convert_units
@@ -135,7 +135,7 @@ def create_obj_for_new_units_or_raise(
135
135
  )
136
136
  opts["units"] = units
137
137
  opts["auto_created"] = True
138
- opts["created"] = get_utcnow()
138
+ opts["created"] = timezone.now()
139
139
  opts["modified"] = opts["created"]
140
140
  break
141
141
  if opts:
@@ -58,10 +58,10 @@ def load_all_reference_ranges() -> None:
58
58
 
59
59
  def load_reference_ranges(
60
60
  collection_name: str,
61
- normal_data: dict[str, list[Formula]] = None,
62
- grading_data: dict[str, list[Formula]] = None,
63
- reportable_grades: list[int] = None,
64
- reportable_grades_exceptions: dict[str, list[int]] = None,
61
+ normal_data: dict[str, list[Formula]],
62
+ grading_data: dict[str, list[Formula]],
63
+ reportable_grades: list[int],
64
+ reportable_grades_exceptions: dict[str, list[int]] | None = None,
65
65
  keep_existing: bool | None = None,
66
66
  create_missing_normal: bool | None = None,
67
67
  ) -> ReferenceRangeCollection:
@@ -1,11 +1,11 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import sys
3
4
  from typing import TYPE_CHECKING
4
5
 
5
6
  from dateutil.relativedelta import relativedelta
6
7
  from django.core.exceptions import ObjectDoesNotExist
7
-
8
- from edc_utils import get_utcnow
8
+ from django.utils import timezone
9
9
 
10
10
  from ..exceptions import NotEvaluated
11
11
  from ..formula import Formula
@@ -55,7 +55,7 @@ def update_grading_data(
55
55
  value=value,
56
56
  units=formula_opts.get("units"),
57
57
  gender=gender,
58
- dob=get_utcnow()
58
+ dob=timezone.now()
59
59
  - relativedelta(
60
60
  **{
61
61
  age_opts.get("age_units"): age_opts.get(
@@ -63,12 +63,12 @@ def update_grading_data(
63
63
  )
64
64
  }
65
65
  ),
66
- report_datetime=get_utcnow(),
66
+ report_datetime=timezone.now(),
67
67
  age_units=age_opts.get("age_units"),
68
68
  create_missing_normal=create_missing_normal,
69
69
  )
70
70
  except NotEvaluated as e:
71
- print(e)
71
+ sys.stdout.write(f"{e}\n")
72
72
 
73
73
 
74
74
  def get_reportable_grades(
@@ -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_review_dashboard", "0005_alter_edcpermissions_revision"),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterField(
14
+ model_name="edcpermissions",
15
+ name="device_created",
16
+ field=models.CharField(
17
+ blank=True, default="", max_length=10, verbose_name="Device created"
18
+ ),
19
+ ),
20
+ migrations.AlterField(
21
+ model_name="edcpermissions",
22
+ name="device_modified",
23
+ field=models.CharField(
24
+ blank=True, default="", max_length=10, verbose_name="Device modified"
25
+ ),
26
+ ),
27
+ migrations.AlterField(
28
+ model_name="edcpermissions",
29
+ name="locale_created",
30
+ field=models.CharField(
31
+ blank=True,
32
+ default="",
33
+ help_text="Auto-updated by Modeladmin",
34
+ max_length=10,
35
+ verbose_name="Locale created",
36
+ ),
37
+ ),
38
+ migrations.AlterField(
39
+ model_name="edcpermissions",
40
+ name="locale_modified",
41
+ field=models.CharField(
42
+ blank=True,
43
+ default="",
44
+ help_text="Auto-updated by Modeladmin",
45
+ max_length=10,
46
+ verbose_name="Locale modified",
47
+ ),
48
+ ),
49
+ ]
@@ -1,9 +1,9 @@
1
1
  from dateutil.relativedelta import relativedelta
2
+ from django.utils import timezone
2
3
  from django.utils.timezone import localtime
3
4
 
4
5
  from edc_reportable.age_evaluator import AgeEvaluator as ReportableAgeEvaluator
5
6
  from edc_reportable.exceptions import ValueBoundryError
6
- from edc_utils.date import get_utcnow
7
7
 
8
8
 
9
9
  class AgeEvaluator(ReportableAgeEvaluator):
@@ -27,9 +27,9 @@ class AgeEvaluator(ReportableAgeEvaluator):
27
27
 
28
28
  def in_bounds_or_raise(self, age: int = None, **kwargs):
29
29
  self.reasons_ineligible = None
30
- dob = localtime(get_utcnow() - relativedelta(years=age)).date()
30
+ dob = localtime(timezone.now() - relativedelta(years=age)).date()
31
31
  age_units = "years"
32
- report_datetime = localtime(get_utcnow())
32
+ report_datetime = localtime(timezone.now())
33
33
  return super().in_bounds_or_raise(
34
34
  dob=dob, report_datetime=report_datetime, age_units=age_units
35
35
  )
@@ -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_screening", "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,5 @@
1
1
  from django.db import models
2
-
3
- from edc_utils import get_utcnow
2
+ from django.utils import timezone
4
3
 
5
4
  from ..screening_eligibility import ScreeningEligibility
6
5
 
@@ -9,7 +8,7 @@ class EligibilityFieldsModelMixin(models.Model):
9
8
  eligible = models.BooleanField(default=False)
10
9
 
11
10
  reasons_ineligible = models.TextField(
12
- verbose_name="Reason not eligible", max_length=150, null=True
11
+ verbose_name="Reason not eligible", max_length=150, default=""
13
12
  )
14
13
 
15
14
  eligibility_datetime = models.DateTimeField(
@@ -52,7 +51,7 @@ class EligibilityModelMixin(EligibilityFieldsModelMixin, models.Model):
52
51
  self.screening_identifier = self.identifier_cls().identifier
53
52
  if self.eligible:
54
53
  self.eligibility_datetime = self.get_report_datetime_for_eligibility_datetime()
55
- self.real_eligibility_datetime = get_utcnow()
54
+ self.real_eligibility_datetime = timezone.now()
56
55
  else:
57
56
  self.eligibility_datetime = None
58
57
  self.real_eligibility_datetime = None
@@ -8,6 +8,7 @@ from django.core.validators import (
8
8
  RegexValidator,
9
9
  )
10
10
  from django.db import models
11
+ from django.utils import timezone
11
12
  from django_crypto_fields.fields import EncryptedCharField
12
13
 
13
14
  from edc_constants.choices import GENDER, YES_NO, YES_NO_NA
@@ -15,7 +16,6 @@ from edc_constants.constants import NO, NOT_APPLICABLE
15
16
  from edc_model.validators import datetime_not_future
16
17
  from edc_protocol.validators import datetime_not_before_study_start
17
18
  from edc_sites.model_mixins import SiteModelMixin
18
- from edc_utils.date import get_utcnow
19
19
 
20
20
 
21
21
  class ScreeningFieldsModeMixin(SiteModelMixin, models.Model):
@@ -34,7 +34,7 @@ class ScreeningFieldsModeMixin(SiteModelMixin, models.Model):
34
34
  report_datetime = models.DateTimeField(
35
35
  verbose_name="Report Date and Time",
36
36
  validators=[datetime_not_before_study_start, datetime_not_future],
37
- default=get_utcnow,
37
+ default=timezone.now,
38
38
  help_text="Date and time of report.",
39
39
  )
40
40
 
@@ -54,7 +54,7 @@ class ScreeningFieldsModeMixin(SiteModelMixin, models.Model):
54
54
  validators=[MinValueValidator(0), MaxValueValidator(110)]
55
55
  )
56
56
 
57
- ethnicity = models.CharField(max_length=25, null=True, blank=True)
57
+ ethnicity = models.CharField(max_length=25, default="", blank=True)
58
58
 
59
59
  consent_ability = models.CharField(
60
60
  verbose_name="Participant or legal guardian/representative able and "
@@ -65,8 +65,7 @@ class ScreeningFieldsModeMixin(SiteModelMixin, models.Model):
65
65
 
66
66
  unsuitable_for_study = models.CharField(
67
67
  verbose_name=(
68
- "Is there any other reason the patient is "
69
- "deemed to not be suitable for the study?"
68
+ "Is there any other reason the patient is deemed to not be suitable for the study?"
70
69
  ),
71
70
  max_length=5,
72
71
  choices=YES_NO,
@@ -77,14 +76,13 @@ class ScreeningFieldsModeMixin(SiteModelMixin, models.Model):
77
76
  reasons_unsuitable = models.TextField(
78
77
  verbose_name="Reason not suitable for the study",
79
78
  max_length=150,
80
- null=True,
79
+ default="",
81
80
  blank=True,
82
81
  )
83
82
 
84
83
  unsuitable_agreed = models.CharField(
85
84
  verbose_name=(
86
- "Does the study coordinator agree that the patient "
87
- "is not suitable for the study?"
85
+ "Does the study coordinator agree that the patient is not suitable for the study?"
88
86
  ),
89
87
  max_length=5,
90
88
  choices=YES_NO_NA,
@@ -20,13 +20,12 @@ class SearchSlugModelMixin(models.Model):
20
20
  search_slug_warning = None
21
21
  search_slug_updater_cls = SearchSlugUpdater
22
22
 
23
- def get_search_slug_fields(self) -> list[str]:
24
- return []
23
+ def get_search_slug_fields(self) -> tuple[str] | None:
24
+ return None
25
25
 
26
26
  slug = models.CharField(
27
27
  max_length=250,
28
28
  default="",
29
- null=True,
30
29
  editable=False,
31
30
  db_index=True,
32
31
  help_text="a field used for quick search",
edc_search/search_slug.py CHANGED
@@ -6,6 +6,7 @@ from typing import TYPE_CHECKING
6
6
  from django.apps import apps as django_apps
7
7
  from django.core.management.color import color_style
8
8
  from django.utils.text import slugify
9
+ from django_crypto_fields.fields import BaseField
9
10
 
10
11
  from .constants import SEARCH_SLUG_SEP
11
12
 
@@ -20,7 +21,9 @@ if TYPE_CHECKING:
20
21
 
21
22
 
22
23
  class SearchSlug:
23
- def __init__(self, obj: Model | SearchSlugModelMixin = None, fields: list[str] = None):
24
+ def __init__(
25
+ self, obj: Model | SearchSlugModelMixin = None, fields: tuple[str] | None = None
26
+ ):
24
27
  self.warning = None
25
28
  self.slug = ""
26
29
  self.model_cls = None
@@ -41,10 +44,8 @@ class SearchSlug:
41
44
  sys.stdout.write(style.WARNING(self.warning))
42
45
  self.slug = slug[:250]
43
46
 
44
- def get_safe_fields(self, fields):
45
- from django_crypto_fields.fields import BaseField
46
-
47
- encrypted_fields = [
48
- fld.name for fld in self.model_cls._meta.fields if isinstance(fld, BaseField)
49
- ]
50
- return [f for f in fields if f not in encrypted_fields]
47
+ def get_safe_fields(self, fields) -> tuple[str]:
48
+ encrypted_fields = tuple(
49
+ [fld.name for fld in self.model_cls._meta.fields if isinstance(fld, BaseField)]
50
+ )
51
+ return tuple([f for f in fields if f not in encrypted_fields])
edc_search/updater.py CHANGED
@@ -13,14 +13,14 @@ if TYPE_CHECKING:
13
13
  pass
14
14
 
15
15
 
16
- class SearchSlugDuplicateFields(Exception):
16
+ class SearchSlugDuplicateFields(Exception): # noqa: N818
17
17
  pass
18
18
 
19
19
 
20
20
  class SearchSlugUpdater:
21
21
  search_slug_cls = SearchSlug
22
22
 
23
- def __init__(self, fields: list[str], model_obj: Model | SearchSlugModelMixin = None):
23
+ def __init__(self, fields: tuple[str], model_obj: Model | SearchSlugModelMixin = None):
24
24
  if len(fields) > len(list(set(fields))):
25
25
  raise SearchSlugDuplicateFields(
26
26
  f"Duplicate search slug fields detected. Got {fields}. See {self!r}"
@@ -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
  (