clinicedc 2.0.6__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 (386) hide show
  1. {clinicedc-2.0.6.dist-info → clinicedc-2.0.7.dist-info}/METADATA +2 -2
  2. {clinicedc-2.0.6.dist-info → clinicedc-2.0.7.dist-info}/RECORD +386 -335
  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/utils.py +1 -1
  385. {clinicedc-2.0.6.dist-info → clinicedc-2.0.7.dist-info}/WHEEL +0 -0
  386. {clinicedc-2.0.6.dist-info → clinicedc-2.0.7.dist-info}/licenses/LICENSE +0 -0
@@ -4,6 +4,7 @@ import django_audit_fields.fields.hostname_modification_field
4
4
  import django_audit_fields.fields.userfield
5
5
  import django_audit_fields.models.audit_model_mixin
6
6
  from django.db import migrations, models
7
+ import django.utils.timezone
7
8
 
8
9
 
9
10
  class Migration(migrations.Migration):
@@ -13,9 +14,7 @@ class Migration(migrations.Migration):
13
14
  migrations.AlterField(
14
15
  model_name="historicalregisteredsubject",
15
16
  name="created",
16
- field=models.DateTimeField(
17
- blank=True, default=django_audit_fields.models.audit_model_mixin.utcnow
18
- ),
17
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now),
19
18
  ),
20
19
  migrations.AlterField(
21
20
  model_name="historicalregisteredsubject",
@@ -29,9 +28,7 @@ class Migration(migrations.Migration):
29
28
  migrations.AlterField(
30
29
  model_name="historicalregisteredsubject",
31
30
  name="modified",
32
- field=models.DateTimeField(
33
- blank=True, default=django_audit_fields.models.audit_model_mixin.utcnow
34
- ),
31
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now),
35
32
  ),
36
33
  migrations.AlterField(
37
34
  model_name="historicalregisteredsubject",
@@ -56,9 +53,7 @@ class Migration(migrations.Migration):
56
53
  migrations.AlterField(
57
54
  model_name="registeredsubject",
58
55
  name="created",
59
- field=models.DateTimeField(
60
- blank=True, default=django_audit_fields.models.audit_model_mixin.utcnow
61
- ),
56
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now),
62
57
  ),
63
58
  migrations.AlterField(
64
59
  model_name="registeredsubject",
@@ -72,9 +67,7 @@ class Migration(migrations.Migration):
72
67
  migrations.AlterField(
73
68
  model_name="registeredsubject",
74
69
  name="modified",
75
- field=models.DateTimeField(
76
- blank=True, default=django_audit_fields.models.audit_model_mixin.utcnow
77
- ),
70
+ field=models.DateTimeField(blank=True, default=django.utils.timezone.now),
78
71
  ),
79
72
  migrations.AlterField(
80
73
  model_name="registeredsubject",
@@ -0,0 +1,302 @@
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
+ (
10
+ "edc_registration",
11
+ "0032_alter_historicalregisteredsubject_revision_and_more",
12
+ ),
13
+ ]
14
+
15
+ operations = [
16
+ migrations.AlterField(
17
+ model_name="historicalregisteredsubject",
18
+ name="additional_key",
19
+ field=models.CharField(
20
+ default="",
21
+ editable=False,
22
+ help_text="A uuid (or some other text value) to be added to bypass the unique constraint of just firstname, initials, and dob.The default constraint proves limiting since the source model usually has some other attribute in additional to first_name, initials and dob which is not captured in this model",
23
+ max_length=36,
24
+ verbose_name="-",
25
+ ),
26
+ ),
27
+ migrations.AlterField(
28
+ model_name="historicalregisteredsubject",
29
+ name="comment",
30
+ field=models.TextField(
31
+ blank=True, default="", max_length=250, verbose_name="Comment"
32
+ ),
33
+ ),
34
+ migrations.AlterField(
35
+ model_name="historicalregisteredsubject",
36
+ name="device_created",
37
+ field=models.CharField(
38
+ blank=True, default="", max_length=10, verbose_name="Device created"
39
+ ),
40
+ ),
41
+ migrations.AlterField(
42
+ model_name="historicalregisteredsubject",
43
+ name="device_modified",
44
+ field=models.CharField(
45
+ blank=True, default="", max_length=10, verbose_name="Device modified"
46
+ ),
47
+ ),
48
+ migrations.AlterField(
49
+ model_name="historicalregisteredsubject",
50
+ name="dm_comment",
51
+ field=models.CharField(
52
+ default="",
53
+ editable=False,
54
+ max_length=150,
55
+ verbose_name="Data Management comment",
56
+ ),
57
+ ),
58
+ migrations.AlterField(
59
+ model_name="historicalregisteredsubject",
60
+ name="ethnicity",
61
+ field=models.CharField(blank=True, default="", max_length=15),
62
+ ),
63
+ migrations.AlterField(
64
+ model_name="historicalregisteredsubject",
65
+ name="gender",
66
+ field=models.CharField(
67
+ choices=[("M", "Male"), ("F", "Female")],
68
+ default="",
69
+ max_length=1,
70
+ verbose_name="Gender",
71
+ ),
72
+ ),
73
+ migrations.AlterField(
74
+ model_name="historicalregisteredsubject",
75
+ name="locale_created",
76
+ field=models.CharField(
77
+ blank=True,
78
+ default="",
79
+ help_text="Auto-updated by Modeladmin",
80
+ max_length=10,
81
+ verbose_name="Locale created",
82
+ ),
83
+ ),
84
+ migrations.AlterField(
85
+ model_name="historicalregisteredsubject",
86
+ name="locale_modified",
87
+ field=models.CharField(
88
+ blank=True,
89
+ default="",
90
+ help_text="Auto-updated by Modeladmin",
91
+ max_length=10,
92
+ verbose_name="Locale modified",
93
+ ),
94
+ ),
95
+ migrations.AlterField(
96
+ model_name="historicalregisteredsubject",
97
+ name="randomization_list_model",
98
+ field=models.CharField(default="", max_length=150),
99
+ ),
100
+ migrations.AlterField(
101
+ model_name="historicalregisteredsubject",
102
+ name="registration_identifier",
103
+ field=models.CharField(blank=True, default="", max_length=36),
104
+ ),
105
+ migrations.AlterField(
106
+ model_name="historicalregisteredsubject",
107
+ name="registration_status",
108
+ field=models.CharField(
109
+ blank=True,
110
+ default="",
111
+ max_length=25,
112
+ verbose_name="Registration status",
113
+ ),
114
+ ),
115
+ migrations.AlterField(
116
+ model_name="historicalregisteredsubject",
117
+ name="relative_identifier",
118
+ field=models.CharField(
119
+ blank=True,
120
+ default="",
121
+ help_text="For example, mother's identifier, if available / appropriate",
122
+ max_length=36,
123
+ verbose_name="Identifier of immediate relation",
124
+ ),
125
+ ),
126
+ migrations.AlterField(
127
+ model_name="historicalregisteredsubject",
128
+ name="screening_identifier",
129
+ field=models.CharField(blank=True, default="", max_length=36),
130
+ ),
131
+ migrations.AlterField(
132
+ model_name="historicalregisteredsubject",
133
+ name="sid",
134
+ field=models.CharField(
135
+ blank=True, default="", max_length=15, verbose_name="SID"
136
+ ),
137
+ ),
138
+ migrations.AlterField(
139
+ model_name="historicalregisteredsubject",
140
+ name="subject_consent_id",
141
+ field=models.CharField(blank=True, default="", max_length=100),
142
+ ),
143
+ migrations.AlterField(
144
+ model_name="historicalregisteredsubject",
145
+ name="subject_identifier_aka",
146
+ field=models.CharField(
147
+ default="",
148
+ editable=False,
149
+ help_text="track a previously allocated identifier.",
150
+ max_length=50,
151
+ verbose_name="Subject Identifier a.k.a",
152
+ ),
153
+ ),
154
+ migrations.AlterField(
155
+ model_name="historicalregisteredsubject",
156
+ name="subject_type",
157
+ field=models.CharField(blank=True, default="", max_length=25),
158
+ ),
159
+ migrations.AlterField(
160
+ model_name="registeredsubject",
161
+ name="additional_key",
162
+ field=models.CharField(
163
+ default="",
164
+ editable=False,
165
+ help_text="A uuid (or some other text value) to be added to bypass the unique constraint of just firstname, initials, and dob.The default constraint proves limiting since the source model usually has some other attribute in additional to first_name, initials and dob which is not captured in this model",
166
+ max_length=36,
167
+ verbose_name="-",
168
+ ),
169
+ ),
170
+ migrations.AlterField(
171
+ model_name="registeredsubject",
172
+ name="comment",
173
+ field=models.TextField(
174
+ blank=True, default="", max_length=250, verbose_name="Comment"
175
+ ),
176
+ ),
177
+ migrations.AlterField(
178
+ model_name="registeredsubject",
179
+ name="device_created",
180
+ field=models.CharField(
181
+ blank=True, default="", max_length=10, verbose_name="Device created"
182
+ ),
183
+ ),
184
+ migrations.AlterField(
185
+ model_name="registeredsubject",
186
+ name="device_modified",
187
+ field=models.CharField(
188
+ blank=True, default="", max_length=10, verbose_name="Device modified"
189
+ ),
190
+ ),
191
+ migrations.AlterField(
192
+ model_name="registeredsubject",
193
+ name="dm_comment",
194
+ field=models.CharField(
195
+ default="",
196
+ editable=False,
197
+ max_length=150,
198
+ verbose_name="Data Management comment",
199
+ ),
200
+ ),
201
+ migrations.AlterField(
202
+ model_name="registeredsubject",
203
+ name="ethnicity",
204
+ field=models.CharField(blank=True, default="", max_length=15),
205
+ ),
206
+ migrations.AlterField(
207
+ model_name="registeredsubject",
208
+ name="gender",
209
+ field=models.CharField(
210
+ choices=[("M", "Male"), ("F", "Female")],
211
+ default="",
212
+ max_length=1,
213
+ verbose_name="Gender",
214
+ ),
215
+ ),
216
+ migrations.AlterField(
217
+ model_name="registeredsubject",
218
+ name="locale_created",
219
+ field=models.CharField(
220
+ blank=True,
221
+ default="",
222
+ help_text="Auto-updated by Modeladmin",
223
+ max_length=10,
224
+ verbose_name="Locale created",
225
+ ),
226
+ ),
227
+ migrations.AlterField(
228
+ model_name="registeredsubject",
229
+ name="locale_modified",
230
+ field=models.CharField(
231
+ blank=True,
232
+ default="",
233
+ help_text="Auto-updated by Modeladmin",
234
+ max_length=10,
235
+ verbose_name="Locale modified",
236
+ ),
237
+ ),
238
+ migrations.AlterField(
239
+ model_name="registeredsubject",
240
+ name="randomization_list_model",
241
+ field=models.CharField(default="", max_length=150),
242
+ ),
243
+ migrations.AlterField(
244
+ model_name="registeredsubject",
245
+ name="registration_identifier",
246
+ field=models.CharField(blank=True, default="", max_length=36),
247
+ ),
248
+ migrations.AlterField(
249
+ model_name="registeredsubject",
250
+ name="registration_status",
251
+ field=models.CharField(
252
+ blank=True,
253
+ default="",
254
+ max_length=25,
255
+ verbose_name="Registration status",
256
+ ),
257
+ ),
258
+ migrations.AlterField(
259
+ model_name="registeredsubject",
260
+ name="relative_identifier",
261
+ field=models.CharField(
262
+ blank=True,
263
+ default="",
264
+ help_text="For example, mother's identifier, if available / appropriate",
265
+ max_length=36,
266
+ verbose_name="Identifier of immediate relation",
267
+ ),
268
+ ),
269
+ migrations.AlterField(
270
+ model_name="registeredsubject",
271
+ name="screening_identifier",
272
+ field=models.CharField(blank=True, default="", max_length=36),
273
+ ),
274
+ migrations.AlterField(
275
+ model_name="registeredsubject",
276
+ name="sid",
277
+ field=models.CharField(
278
+ blank=True, default="", max_length=15, verbose_name="SID"
279
+ ),
280
+ ),
281
+ migrations.AlterField(
282
+ model_name="registeredsubject",
283
+ name="subject_consent_id",
284
+ field=models.CharField(blank=True, default="", max_length=100),
285
+ ),
286
+ migrations.AlterField(
287
+ model_name="registeredsubject",
288
+ name="subject_identifier_aka",
289
+ field=models.CharField(
290
+ default="",
291
+ editable=False,
292
+ help_text="track a previously allocated identifier.",
293
+ max_length=50,
294
+ verbose_name="Subject Identifier a.k.a",
295
+ ),
296
+ ),
297
+ migrations.AlterField(
298
+ model_name="registeredsubject",
299
+ name="subject_type",
300
+ field=models.CharField(blank=True, default="", max_length=25),
301
+ ),
302
+ ]
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import contextlib
3
4
  from typing import TYPE_CHECKING
4
5
 
5
6
  from django.core.exceptions import ObjectDoesNotExist
@@ -64,10 +65,8 @@ class UpdatesOrCreatesRegistrationModelMixin(models.Model):
64
65
 
65
66
  Converts UUID to string using .hex.
66
67
  """
67
- try:
68
+ with contextlib.suppress(AttributeError):
68
69
  value = str(value.hex)
69
- except AttributeError:
70
- pass
71
70
  return value
72
71
 
73
72
  @property
@@ -44,7 +44,7 @@ class RegisteredSubject(UniqueSubjectIdentifierModelMixin, SiteModelMixin, BaseU
44
44
  validators=[
45
45
  RegexValidator(
46
46
  regex=r"^[A-Z]{2,3}$",
47
- message=("Ensure initials consist of letters only in upper case, no spaces."),
47
+ message="Ensure initials consist of letters only in upper case, no spaces.",
48
48
  )
49
49
  ],
50
50
  null=True,
@@ -62,27 +62,27 @@ class RegisteredSubject(UniqueSubjectIdentifierModelMixin, SiteModelMixin, BaseU
62
62
  )
63
63
 
64
64
  gender = models.CharField(
65
- verbose_name="Gender", max_length=1, choices=GENDER, null=True, blank=False
65
+ verbose_name="Gender", max_length=1, choices=GENDER, default="", blank=False
66
66
  )
67
67
 
68
68
  ethnicity = models.CharField(
69
69
  max_length=15,
70
- null=True,
70
+ default="",
71
71
  blank=True,
72
72
  )
73
73
 
74
- subject_consent_id = models.CharField(max_length=100, null=True, blank=True)
74
+ subject_consent_id = models.CharField(max_length=100, default="", blank=True)
75
75
 
76
- registration_identifier = models.CharField(max_length=36, null=True, blank=True)
76
+ registration_identifier = models.CharField(max_length=36, default="", blank=True)
77
77
 
78
- sid = models.CharField(verbose_name="SID", max_length=15, null=True, blank=True)
78
+ sid = models.CharField(verbose_name="SID", max_length=15, default="", blank=True)
79
79
 
80
- subject_type = models.CharField(max_length=25, null=True, blank=True)
80
+ subject_type = models.CharField(max_length=25, default="", blank=True)
81
81
 
82
82
  relative_identifier = models.CharField(
83
83
  verbose_name="Identifier of immediate relation",
84
84
  max_length=36,
85
- null=True,
85
+ default="",
86
86
  blank=True,
87
87
  help_text="For example, mother's identifier, if available / appropriate",
88
88
  )
@@ -91,7 +91,7 @@ class RegisteredSubject(UniqueSubjectIdentifierModelMixin, SiteModelMixin, BaseU
91
91
 
92
92
  identity_type = IdentityTypeField(null=True, blank=True)
93
93
 
94
- screening_identifier = models.CharField(max_length=36, null=True, blank=True)
94
+ screening_identifier = models.CharField(max_length=36, default="", blank=True)
95
95
 
96
96
  screening_datetime = models.DateTimeField(null=True, blank=True)
97
97
 
@@ -104,19 +104,18 @@ class RegisteredSubject(UniqueSubjectIdentifierModelMixin, SiteModelMixin, BaseU
104
104
  randomization_datetime = models.DateTimeField(null=True, blank=True)
105
105
 
106
106
  registration_status = models.CharField(
107
- verbose_name="Registration status", max_length=25, null=True, blank=True
107
+ verbose_name="Registration status", max_length=25, default="", blank=True
108
108
  )
109
109
 
110
110
  consent_datetime = models.DateTimeField(null=True, blank=True)
111
111
 
112
- comment = models.TextField(verbose_name="Comment", max_length=250, null=True, blank=True)
112
+ comment = models.TextField(verbose_name="Comment", max_length=250, default="", blank=True)
113
113
 
114
114
  additional_key = models.CharField(
115
115
  max_length=36,
116
116
  verbose_name="-",
117
117
  editable=False,
118
- default=None,
119
- null=True,
118
+ default="",
120
119
  help_text=(
121
120
  "A uuid (or some other text value) to be added to bypass the "
122
121
  "unique constraint of just firstname, initials, and dob."
@@ -130,11 +129,11 @@ class RegisteredSubject(UniqueSubjectIdentifierModelMixin, SiteModelMixin, BaseU
130
129
  dm_comment = models.CharField(
131
130
  verbose_name="Data Management comment",
132
131
  max_length=150,
133
- null=True,
132
+ default="",
134
133
  editable=False,
135
134
  )
136
135
 
137
- randomization_list_model = models.CharField(max_length=150, null=True)
136
+ randomization_list_model = models.CharField(max_length=150, default="")
138
137
 
139
138
  objects = RegisteredSubjectManager()
140
139
 
@@ -157,7 +156,7 @@ class RegisteredSubject(UniqueSubjectIdentifierModelMixin, SiteModelMixin, BaseU
157
156
  def __str__(self):
158
157
  return self.masked_subject_identifier
159
158
 
160
- natural_key.dependencies = ["sites.Site"]
159
+ natural_key.dependencies = ("sites.Site",)
161
160
 
162
161
  def update_subject_identifier_on_save(self):
163
162
  """Overridden to not set the subject identifier on save."""
@@ -202,13 +201,15 @@ class RegisteredSubject(UniqueSubjectIdentifierModelMixin, SiteModelMixin, BaseU
202
201
  if self.id and self.subject_identifier_is_set:
203
202
  with transaction.atomic():
204
203
  obj = self.__class__.objects.get(pk=self.id)
205
- if obj.subject_identifier != self.subject_identifier_as_pk.hex:
206
- if self.subject_identifier != obj.subject_identifier:
207
- raise RegisteredSubjectError(
208
- "Subject identifier cannot be changed for "
209
- "existing registered subject. "
210
- f"Got {self.subject_identifier} <> {obj.subject_identifier}."
211
- )
204
+ if obj.subject_identifier not in (
205
+ self.subject_identifier_as_pk.hex,
206
+ self.subject_identifier,
207
+ ):
208
+ raise RegisteredSubjectError(
209
+ "Subject identifier cannot be changed for "
210
+ "existing registered subject. "
211
+ f"Got {self.subject_identifier} <> {obj.subject_identifier}."
212
+ )
212
213
 
213
214
  def raise_on_duplicate(self, attrname):
214
215
  """Checks if the subject identifier (or other attr) is in use,
@@ -246,12 +247,12 @@ class RegisteredSubject(UniqueSubjectIdentifierModelMixin, SiteModelMixin, BaseU
246
247
  class Meta(UniqueSubjectIdentifierModelMixin.Meta, BaseUuidModel.Meta):
247
248
  verbose_name = "Registered Subject"
248
249
  verbose_name_plural = "Registered Subjects"
249
- constraints = [
250
+ constraints = (
250
251
  UniqueConstraint(
251
252
  fields=["first_name", "dob", "initials", "additional_key"],
252
253
  name="%(app_label)s_%(class)s_first_name_uniq",
253
- )
254
- ]
254
+ ),
255
+ )
255
256
  indexes = (
256
257
  *BaseUuidModel.Meta.indexes,
257
258
  models.Index(fields=["first_name", "dob", "initials", "additional_key"]),
@@ -2,7 +2,9 @@ from __future__ import annotations
2
2
 
3
3
  from datetime import date, datetime
4
4
 
5
- from edc_utils import age, get_utcnow
5
+ from django.utils import timezone
6
+
7
+ from edc_utils import age
6
8
 
7
9
  from .evaluator import Evaluator
8
10
 
@@ -38,7 +40,7 @@ class AgeEvaluator(Evaluator):
38
40
  report_datetime: datetime = None,
39
41
  age_units: str | None = None,
40
42
  ) -> bool:
41
- report_datetime = report_datetime or get_utcnow()
43
+ report_datetime = report_datetime or timezone.now()
42
44
  age_units = age_units or "years"
43
45
  rdelta = age(dob, report_datetime)
44
46
  value = getattr(rdelta, self.units)
edc_reportable/formula.py CHANGED
@@ -41,8 +41,8 @@ class Formula:
41
41
  age_lower_inclusive: bool | None = None
42
42
  age_upper_inclusive: bool | None = None
43
43
  grade: int | None = None
44
- lln: str | None = field(default=None, init=False, repr=False)
45
- uln: str | None = field(default=None, init=False, repr=False)
44
+ lln: str | None = field(default="", init=False, repr=False)
45
+ uln: str | None = field(default="", init=False, repr=False)
46
46
  lower_operator: str = field(default="", init=False, repr=False)
47
47
  upper_operator: str = field(default="", init=False, repr=False)
48
48
  age_lower_operator: str = field(default="", init=False, repr=False)
@@ -108,8 +108,8 @@ class Formula:
108
108
 
109
109
  @staticmethod
110
110
  def parse_fragment(fragment: str) -> tuple[float, bool, str | None]:
111
- limit_normal: str | None = None
112
- inclusive = True if "=" in fragment else False
111
+ limit_normal: str = ""
112
+ inclusive = "=" in fragment
113
113
  try:
114
114
  value = float(
115
115
  fragment.replace("<", "")
@@ -130,7 +130,7 @@ def formula(phrase, **kwargs):
130
130
  return Formula(phrase, **kwargs).description
131
131
 
132
132
 
133
- def dummy_formula(phrase: str = None, units: str = None) -> Formula:
133
+ def dummy_formula(phrase: str, units: str) -> Formula:
134
134
  return Formula(
135
135
  phrase or "0<=x",
136
136
  units=units,
@@ -8,10 +8,10 @@ import django_audit_fields.fields.uuid_auto_field
8
8
  import django_audit_fields.models.audit_model_mixin
9
9
  import django_revision.revision_field
10
10
  from django.db import migrations, models
11
+ import django.utils.timezone
11
12
 
12
13
 
13
14
  class Migration(migrations.Migration):
14
-
15
15
  initial = True
16
16
 
17
17
  dependencies = []
@@ -35,14 +35,14 @@ class Migration(migrations.Migration):
35
35
  "created",
36
36
  models.DateTimeField(
37
37
  blank=True,
38
- default=django_audit_fields.models.audit_model_mixin.utcnow,
38
+ default=django.utils.timezone.now,
39
39
  ),
40
40
  ),
41
41
  (
42
42
  "modified",
43
43
  models.DateTimeField(
44
44
  blank=True,
45
- default=django_audit_fields.models.audit_model_mixin.utcnow,
45
+ default=django.utils.timezone.now,
46
46
  ),
47
47
  ),
48
48
  (
@@ -167,14 +167,14 @@ class Migration(migrations.Migration):
167
167
  "created",
168
168
  models.DateTimeField(
169
169
  blank=True,
170
- default=django_audit_fields.models.audit_model_mixin.utcnow,
170
+ default=django.utils.timezone.now,
171
171
  ),
172
172
  ),
173
173
  (
174
174
  "modified",
175
175
  models.DateTimeField(
176
176
  blank=True,
177
- default=django_audit_fields.models.audit_model_mixin.utcnow,
177
+ default=django.utils.timezone.now,
178
178
  ),
179
179
  ),
180
180
  (
@@ -309,14 +309,14 @@ class Migration(migrations.Migration):
309
309
  "created",
310
310
  models.DateTimeField(
311
311
  blank=True,
312
- default=django_audit_fields.models.audit_model_mixin.utcnow,
312
+ default=django.utils.timezone.now,
313
313
  ),
314
314
  ),
315
315
  (
316
316
  "modified",
317
317
  models.DateTimeField(
318
318
  blank=True,
319
- default=django_audit_fields.models.audit_model_mixin.utcnow,
319
+ default=django.utils.timezone.now,
320
320
  ),
321
321
  ),
322
322
  (
@@ -9,10 +9,10 @@ import django_audit_fields.fields.uuid_auto_field
9
9
  import django_audit_fields.models.audit_model_mixin
10
10
  import django_revision.revision_field
11
11
  from django.db import migrations, models
12
+ import django.utils.timezone
12
13
 
13
14
 
14
15
  class Migration(migrations.Migration):
15
-
16
16
  dependencies = [
17
17
  ("edc_reportable", "0002_alter_gradingdata_age_upper_and_more"),
18
18
  ]
@@ -113,14 +113,14 @@ class Migration(migrations.Migration):
113
113
  "created",
114
114
  models.DateTimeField(
115
115
  blank=True,
116
- default=django_audit_fields.models.audit_model_mixin.utcnow,
116
+ default=django.utils.timezone.now,
117
117
  ),
118
118
  ),
119
119
  (
120
120
  "modified",
121
121
  models.DateTimeField(
122
122
  blank=True,
123
- default=django_audit_fields.models.audit_model_mixin.utcnow,
123
+ default=django.utils.timezone.now,
124
124
  ),
125
125
  ),
126
126
  (