meta-edc 0.3.39__py3-none-any.whl → 1.4.0__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.
Files changed (637) hide show
  1. meta_ae/action_items.py +38 -27
  2. meta_ae/admin/__init__.py +11 -0
  3. meta_ae/admin/ae_initial_admin.py +5 -2
  4. meta_ae/admin/ae_susar_admin.py +1 -1
  5. meta_ae/admin/death_report_admin.py +1 -1
  6. meta_ae/admin/modeladmin_mixins.py +14 -15
  7. meta_ae/baker_recipes.py +4 -6
  8. meta_ae/choices.py +1 -1
  9. meta_ae/forms/__init__.py +13 -0
  10. meta_ae/forms/death_report_form.py +1 -1
  11. meta_ae/forms/modelform_mixins.py +2 -2
  12. meta_ae/list_data.py +1 -1
  13. meta_ae/migrations/0001_initial.py +27 -27
  14. meta_ae/migrations/0006_aelocalreview_aesponsorreview.py +5 -5
  15. meta_ae/migrations/0017_auto_20221130_2257.py +1 -1
  16. meta_ae/migrations/0022_historicalhospitalization_hospitalization.py +5 -13
  17. meta_ae/migrations/0023_alter_aefollowup_action_identifier_and_more.py +2017 -0
  18. meta_ae/model_mixins/__init__.py +2 -0
  19. meta_ae/model_mixins/ae_review_model_mixin.py +6 -6
  20. meta_ae/model_mixins/death_report_model_mixin.py +3 -3
  21. meta_ae/models/__init__.py +13 -0
  22. meta_ae/models/hospitalization.py +3 -3
  23. meta_ae/pdf_reports/__init__.py +2 -0
  24. meta_ae/templatetags/meta_ae_extras.py +4 -6
  25. meta_analytics/.DS_Store +0 -0
  26. meta_analytics/README.rst +1 -2
  27. meta_analytics/dataframes/__init__.py +27 -0
  28. meta_analytics/dataframes/constants.py +5 -2
  29. meta_analytics/dataframes/get_eos_df.py +16 -4
  30. meta_analytics/dataframes/get_glucose_df.py +166 -0
  31. meta_analytics/dataframes/get_glucose_fbg_df.py +26 -0
  32. meta_analytics/dataframes/get_glucose_fbg_ogtt_df.py +21 -0
  33. meta_analytics/dataframes/get_last_imp_visits_df.py +12 -10
  34. meta_analytics/dataframes/glucose_endpoints/__init__.py +2 -0
  35. meta_analytics/dataframes/glucose_endpoints/endpoint_by_date.py +125 -124
  36. meta_analytics/dataframes/glucose_endpoints/glucose_endpoints_by_date.py +111 -235
  37. meta_analytics/dataframes/screening/__init__.py +2 -0
  38. meta_analytics/dataframes/screening/get_glucose_tested_only_df.py +1 -2
  39. meta_analytics/dataframes/screening/get_screening_df.py +9 -15
  40. meta_analytics/dataframes/utils.py +21 -12
  41. meta_analytics/get_tables.py +1 -2
  42. meta_analytics/tables/__init__.py +2 -0
  43. meta_analytics/tables/enrolled/glucose.py +2 -1
  44. meta_analytics/utils.py +81 -0
  45. meta_auth/auths.py +1 -1
  46. meta_consent/action_items.py +22 -3
  47. meta_consent/admin/__init__.py +7 -0
  48. meta_consent/admin/actions/__init__.py +2 -0
  49. meta_consent/admin/actions/create_missing_prescriptions.py +2 -2
  50. meta_consent/admin/list_filters.py +22 -0
  51. meta_consent/admin/modeladmin_mixins.py +4 -5
  52. meta_consent/admin/subject_consent_v1_ext_admin.py +93 -0
  53. meta_consent/baker_recipes.py +7 -7
  54. meta_consent/consents.py +15 -2
  55. meta_consent/constants.py +1 -0
  56. meta_consent/form_validators/__init__.py +2 -0
  57. meta_consent/forms/__init__.py +8 -0
  58. meta_consent/forms/subject_consent_v1_ext_form.py +47 -0
  59. meta_consent/forms/subject_reconsent_form.py +4 -4
  60. meta_consent/management/commands/create_missing_prescriptions.py +5 -3
  61. meta_consent/migrations/0001_initial.py +9 -9
  62. meta_consent/migrations/0024_historicalsubjectconsentv1.py +3 -8
  63. meta_consent/migrations/0026_historicalsubjectconsentv1ext_subjectconsentv1ext.py +535 -0
  64. meta_consent/migrations/0027_auto_20250111_0344.py +30 -0
  65. meta_consent/migrations/0028_historicalsubjectconsentv1ext_assessment_score_and_more.py +162 -0
  66. meta_consent/migrations/0029_alter_historicalsubjectconsentv1ext_agrees_to_extension_and_more.py +33 -0
  67. meta_consent/migrations/0030_auto_20250120_2114.py +40 -0
  68. meta_consent/migrations/0031_alter_historicalsubjectconsent_guardian_name_and_more.py +124 -0
  69. meta_consent/migrations/0032_alter_historicalsubjectconsent_device_created_and_more.py +678 -0
  70. meta_consent/migrations/0033_historicalsubjectconsentspfq_subjectconsentspfq.py +615 -0
  71. meta_consent/migrations/0034_remove_subjectconsentspfq_site_and_more.py +23 -0
  72. meta_consent/migrations/0035_alter_historicalsubjectconsent_consent_definition_name_and_more.py +43 -0
  73. meta_consent/models/__init__.py +10 -0
  74. meta_consent/models/model_mixins.py +1 -2
  75. meta_consent/models/signals.py +25 -11
  76. meta_consent/models/subject_consent.py +2 -2
  77. meta_consent/models/subject_consent_v1.py +0 -1
  78. meta_consent/models/subject_consent_v1_ext.py +34 -0
  79. meta_consent/models/subject_reconsent.py +4 -4
  80. meta_dashboard/navbars.py +2 -6
  81. meta_dashboard/patterns.py +1 -1
  82. meta_dashboard/templates/meta_dashboard/{bootstrap3/buttons → buttons}/eligibility_button.html +1 -1
  83. meta_dashboard/templates/meta_dashboard/{bootstrap3/buttons → buttons}/screening_button.html +1 -1
  84. meta_dashboard/templates/meta_dashboard/subject/dashboard/sidebar.html +24 -0
  85. meta_dashboard/templates/meta_dashboard/{bootstrap3/subject → subject}/dashboard/top_bar.html +1 -1
  86. meta_dashboard/templates/meta_dashboard/subject/dashboard.html +14 -0
  87. meta_dashboard/templatetags/meta_dashboard_extras.py +9 -14
  88. meta_dashboard/urls.py +5 -5
  89. meta_dashboard/view_utils/__init__.py +13 -0
  90. meta_dashboard/view_utils/subject_screening_button.py +13 -20
  91. meta_dashboard/views/__init__.py +8 -0
  92. meta_dashboard/views/ae/__init__.py +2 -0
  93. meta_dashboard/views/ae/ae_listboard_view.py +1 -1
  94. meta_dashboard/views/ae/death_report_listboard_view.py +1 -1
  95. meta_dashboard/views/screening/__init__.py +2 -0
  96. meta_dashboard/views/screening/listboard_view.py +2 -3
  97. meta_dashboard/views/subject/__init__.py +2 -0
  98. meta_dashboard/views/subject/dashboard/__init__.py +2 -0
  99. meta_dashboard/views/subject/dashboard/dashboard_view.py +19 -8
  100. meta_dashboard/views/subject/listboard/__init__.py +2 -0
  101. meta_dashboard/views/subject/listboard/listboard_view.py +2 -3
  102. meta_edc/__init__.py +5 -9
  103. meta_edc/admin.py +3 -4
  104. meta_edc/celery.py +2 -2
  105. meta_edc/celery_live.py +19 -0
  106. meta_edc/celery_uat.py +25 -0
  107. meta_edc/management/commands/update_forms_reference.py +16 -14
  108. meta_edc/meta_version.py +2 -2
  109. meta_edc/navbars.py +7 -5
  110. meta_edc/settings/debug.py +13 -4
  111. meta_edc/settings/defaults.py +55 -18
  112. meta_edc/settings/live.py +4 -1
  113. meta_edc/settings/logging.py +9 -4
  114. meta_edc/settings/minimal.py +4 -5
  115. meta_edc/settings/uat.py +3 -1
  116. meta_edc/templates/meta_edc/{bootstrap3/base.html → base.html} +1 -1
  117. meta_edc/templates/meta_edc/{bootstrap3/home.html → home.html} +2 -2
  118. meta_edc/urls.py +3 -1
  119. meta_edc/utils.py +3 -1
  120. meta_edc/views/__init__.py +2 -0
  121. meta_edc/views/home_view.py +1 -2
  122. meta_edc-1.4.0.dist-info/METADATA +174 -0
  123. {meta_edc-0.3.39.dist-info → meta_edc-1.4.0.dist-info}/RECORD +578 -586
  124. meta_edc-1.4.0.dist-info/WHEEL +4 -0
  125. meta_labs/list_data.py +2 -2
  126. meta_labs/reportables.py +80 -11
  127. meta_lists/list_data.py +13 -4
  128. meta_lists/migrations/0008_auto_20200528_1517.py +2 -2
  129. meta_lists/migrations/0019_auto_20250128_0143.py +48 -0
  130. meta_lists/migrations/0020_alter_abnormalfootappearanceobservations_extra_value_and_more.py +404 -0
  131. meta_pharmacy/admin/__init__.py +5 -0
  132. meta_pharmacy/admin/rx_admin.py +1 -0
  133. meta_pharmacy/admin/substitutions_admin.py +3 -3
  134. meta_pharmacy/constants.py +1 -1
  135. meta_pharmacy/forms/__init__.py +2 -0
  136. meta_pharmacy/forms/rx_form.py +0 -1
  137. meta_pharmacy/forms/substitutions_form.py +6 -4
  138. meta_pharmacy/labels/__init__.py +5 -2
  139. meta_pharmacy/labels/draw_label_for_subject_with_barcode.py +4 -1
  140. meta_pharmacy/labels/draw_label_with_test_data.py +2 -2
  141. meta_pharmacy/labels/label_data.py +1 -2
  142. meta_pharmacy/labels/print_sheets.py +4 -6
  143. meta_pharmacy/management/commands/update_initial_pharmacy_data.py +4 -3
  144. meta_pharmacy/migrations/0002_initial.py +7 -20
  145. meta_pharmacy/migrations/0003_auto_20240909_2335.py +3 -2
  146. meta_pharmacy/migrations/0006_lotnumber_label.py +5 -14
  147. meta_pharmacy/migrations/0008_remove_lotnumber_medication_and_more.py +5 -6
  148. meta_pharmacy/migrations/0010_alter_historicallabeldata_device_created_and_more.py +382 -0
  149. meta_pharmacy/models/__init__.py +7 -0
  150. meta_pharmacy/models/label_data.py +4 -5
  151. meta_pharmacy/models/rx_label.py +0 -1
  152. meta_pharmacy/models/substitutions.py +4 -4
  153. meta_pharmacy/prepare_meta_pharmacy.py +1 -1
  154. meta_pharmacy/utils/__init__.py +2 -0
  155. meta_pharmacy/utils/update_initial_pharmacy_data.py +1 -1
  156. meta_prn/action_items.py +44 -45
  157. meta_prn/admin/__init__.py +16 -0
  158. meta_prn/admin/dm_referral_admin.py +2 -1
  159. meta_prn/admin/end_of_study_admin.py +26 -15
  160. meta_prn/admin/loss_to_followup_admin.py +3 -2
  161. meta_prn/admin/off_study_medication_admin.py +5 -6
  162. meta_prn/admin/offschedule_admin.py +12 -11
  163. meta_prn/admin/offschedule_dm_referral_admin.py +11 -10
  164. meta_prn/admin/offschedule_postnatal_admin.py +15 -7
  165. meta_prn/admin/offschedule_pregnancy_admin.py +18 -9
  166. meta_prn/admin/onschedule_admin.py +7 -8
  167. meta_prn/admin/onschedule_dm_referral_admin.py +11 -12
  168. meta_prn/admin/pregnancy_notification_admin.py +5 -6
  169. meta_prn/admin/protocol_incident_admin.py +1 -1
  170. meta_prn/admin/subject_transfer_admin.py +1 -1
  171. meta_prn/baker_recipes.py +10 -10
  172. meta_prn/choices.py +11 -7
  173. meta_prn/constants.py +1 -0
  174. meta_prn/form_validators/__init__.py +5 -0
  175. meta_prn/form_validators/end_of_study.py +65 -20
  176. meta_prn/form_validators/protocol_incident.py +1 -1
  177. meta_prn/forms/__init__.py +13 -0
  178. meta_prn/forms/dm_referral_form.py +2 -8
  179. meta_prn/forms/end_of_study_form.py +1 -1
  180. meta_prn/forms/loss_to_followup_form.py +1 -1
  181. meta_prn/forms/off_study_medication_form.py +2 -2
  182. meta_prn/forms/offschedule_form.py +25 -0
  183. meta_prn/forms/pregnancy_notification_form.py +15 -17
  184. meta_prn/list_data.py +3 -3
  185. meta_prn/migrations/0001_initial.py +25 -25
  186. meta_prn/migrations/0017_auto_20220307_1929.py +5 -5
  187. meta_prn/migrations/0018_auto_20220309_2106.py +9 -9
  188. meta_prn/migrations/0021_auto_20220316_2147.py +13 -13
  189. meta_prn/migrations/0022_auto_20220318_0133.py +9 -9
  190. meta_prn/migrations/0032_historicalegfrnotification_egfrnotification.py +5 -13
  191. meta_prn/migrations/0034_auto_20220630_1110.py +1 -1
  192. meta_prn/migrations/0035_auto_20220630_1140.py +1 -1
  193. meta_prn/migrations/0038_alter_endofstudy_delivery_date_and_more.py +5 -13
  194. meta_prn/migrations/0041_endofstudy_transfer_date_and_more.py +5 -13
  195. meta_prn/migrations/0057_historicalonscheduledmreferral_and_more.py +13 -38
  196. meta_prn/migrations/0060_alter_onschedule_managers_and_more.py +55 -0
  197. meta_prn/migrations/0061_auto_20250115_2025.py +56 -0
  198. meta_prn/migrations/0062_alter_endofstudy_offstudy_reason_and_more.py +72 -0
  199. meta_prn/migrations/0063_historicaloffstudymedication_singleton_field_and_more.py +37 -0
  200. meta_prn/migrations/0064_auto_20250602_2143.py +18 -0
  201. meta_prn/migrations/0065_alter_historicaloffstudymedication_subject_identifier_and_more.py +23 -0
  202. meta_prn/migrations/0066_alter_historicallosstofollowup_subject_identifier_and_more.py +23 -0
  203. meta_prn/migrations/0067_alter_offschedule_managers_and_more.py +2557 -0
  204. meta_prn/migrations/0068_alter_dmreferral_referral_note_and_more.py +235 -0
  205. meta_prn/migrations/0069_alter_historicaloffstudymedication_singleton_field_and_more.py +37 -0
  206. meta_prn/models/__init__.py +20 -0
  207. meta_prn/models/dm_referral.py +2 -2
  208. meta_prn/models/end_of_study.py +28 -23
  209. meta_prn/models/loss_to_followup.py +8 -10
  210. meta_prn/models/off_study_medication.py +7 -4
  211. meta_prn/models/offschedule.py +4 -4
  212. meta_prn/models/pregnancy_notification.py +3 -5
  213. meta_prn/models/protocol_incident.py +5 -2
  214. meta_prn/models/signals.py +16 -14
  215. meta_prn/models/subject_transfer.py +7 -0
  216. meta_prn/templates/meta_prn/eos/additional_instructions.html +3 -0
  217. meta_prn/templates/meta_prn/offschedule/additional_instructions.html +2 -0
  218. meta_rando/migrations/0001_initial.py +5 -5
  219. meta_rando/migrations/0006_alter_historicalrandomizationlist_allocated_user_and_more.py +130 -0
  220. meta_rando/migrations/0007_spfqlist.py +197 -0
  221. meta_rando/migrations/0008_delete_spfqlist.py +16 -0
  222. meta_rando/models/__init__.py +1 -0
  223. meta_rando/{models.py → models/randomization_list.py} +3 -3
  224. meta_rando/randomizers.py +2 -2
  225. meta_reports/__init__.py +2 -0
  226. meta_reports/admin/__init__.py +16 -0
  227. meta_reports/admin/dbviews/__init__.py +13 -0
  228. meta_reports/admin/dbviews/glucose_summary_admin.py +7 -7
  229. meta_reports/admin/dbviews/imp_substitutions_admin.py +14 -13
  230. meta_reports/admin/dbviews/missing_screening_ogtt_admin/__init__.py +5 -0
  231. meta_reports/admin/dbviews/missing_screening_ogtt_admin/note_model_admin.py +27 -3
  232. meta_reports/admin/dbviews/missing_screening_ogtt_admin/unmanaged_model_admin.py +7 -7
  233. meta_reports/admin/dbviews/on_study_missing_lab_values_admin/__init__.py +2 -0
  234. meta_reports/admin/dbviews/on_study_missing_lab_values_admin/unmanaged_model_admin.py +0 -3
  235. meta_reports/admin/dbviews/on_study_missing_values_admin/__init__.py +2 -0
  236. meta_reports/admin/dbviews/on_study_missing_values_admin/unmanaged_model_admin.py +0 -1
  237. meta_reports/admin/dbviews/patient_history_missing_baseline_cd4_admin.py +9 -9
  238. meta_reports/admin/dbviews/unattended_three_in_row2_admin.py +6 -6
  239. meta_reports/admin/dbviews/unattended_three_in_row_admin.py +5 -5
  240. meta_reports/admin/dbviews/unattended_two_in_row_admin.py +5 -5
  241. meta_reports/admin/endpoints_admin.py +1 -1
  242. meta_reports/admin/endpoints_all_admin.py +0 -1
  243. meta_reports/admin/last_imp_refill_admin.py +33 -36
  244. meta_reports/admin/list_filters.py +3 -3
  245. meta_reports/admin/modeladmin_mixins.py +10 -17
  246. meta_reports/death_report.py +2 -2
  247. meta_reports/forms/__init__.py +2 -0
  248. meta_reports/forms/missing_ogtt_note_form.py +3 -4
  249. meta_reports/management/commands/generate_endpoints.py +5 -4
  250. meta_reports/migrations/0035_historicalmissingogttnote_missingogttnote.py +5 -14
  251. meta_reports/migrations/0054_auto_20250422_2003.py +81 -0
  252. meta_reports/migrations/0055_alter_glucosesummary_table.py +17 -0
  253. meta_reports/migrations/0056_auto_20250422_2214.py +54 -0
  254. meta_reports/migrations/0057_auto_20250422_2224.py +54 -0
  255. meta_reports/migrations/0058_auto_20250422_2232.py +54 -0
  256. meta_reports/migrations/0059_alter_endpoints_created_and_more.py +161 -0
  257. meta_reports/migrations/0060_auto_20250926_0242.py +366 -0
  258. meta_reports/migrations/0061_auto_20251004_0043.py +21 -0
  259. meta_reports/migrations/0062_auto_20251004_0106.py +21 -0
  260. meta_reports/models/__init__.py +17 -0
  261. meta_reports/models/dbviews/__init__.py +14 -0
  262. meta_reports/models/dbviews/glucose_summary/__init__.py +2 -0
  263. meta_reports/models/dbviews/glucose_summary/unmanaged_model.py +15 -3
  264. meta_reports/models/dbviews/glucose_summary/view_definition.py +8 -5
  265. meta_reports/models/dbviews/imp_substitutions/__init__.py +2 -0
  266. meta_reports/models/dbviews/imp_substitutions/unmanaged_model.py +1 -2
  267. meta_reports/models/dbviews/imp_substitutions/view_definition.py +1 -1
  268. meta_reports/models/dbviews/missing_screening_ogtt/__init__.py +2 -0
  269. meta_reports/models/dbviews/missing_screening_ogtt/note_model.py +2 -2
  270. meta_reports/models/dbviews/missing_screening_ogtt/unmanaged_model.py +4 -3
  271. meta_reports/models/dbviews/on_study_missing_lab_values/__init__.py +2 -0
  272. meta_reports/models/dbviews/on_study_missing_lab_values/qa_cases.py +13 -11
  273. meta_reports/models/dbviews/on_study_missing_lab_values/unmanged_model.py +0 -1
  274. meta_reports/models/dbviews/on_study_missing_values/__init__.py +2 -0
  275. meta_reports/models/dbviews/on_study_missing_values/qa_cases.py +19 -1
  276. meta_reports/models/dbviews/on_study_missing_values/unmanged_model.py +0 -1
  277. meta_reports/models/dbviews/patient_history_missing_baseline_cd4/__init__.py +2 -0
  278. meta_reports/models/dbviews/patient_history_missing_baseline_cd4/unmanaged_model.py +0 -1
  279. meta_reports/models/dbviews/unattended_three_in_row/__init__.py +2 -0
  280. meta_reports/models/dbviews/unattended_three_in_row/unmanaged_model.py +0 -1
  281. meta_reports/models/dbviews/unattended_three_in_row2/__init__.py +2 -0
  282. meta_reports/models/dbviews/unattended_three_in_row2/unmanaged_model.py +0 -1
  283. meta_reports/models/dbviews/unattended_two_in_row/__init__.py +2 -0
  284. meta_reports/models/dbviews/unattended_two_in_row/unmanaged_model.py +0 -1
  285. meta_reports/models/endpoints.py +8 -4
  286. meta_reports/models/last_imp_refill.py +2 -3
  287. meta_reports/pdf_report.py +2 -2
  288. meta_reports/tasks.py +4 -3
  289. meta_reports/templates/meta_reports/columns/subject_identifier_column.html +1 -1
  290. meta_reports/templates/meta_reports/endpoints_all_change_list_note.html +1 -1
  291. meta_reports/templates/meta_reports/endpoints_change_list_note.html +1 -1
  292. meta_reports/templates/meta_reports/last_imp_refill/changelist_note.html +13 -0
  293. meta_screening/admin/__init__.py +8 -0
  294. meta_screening/admin/fieldsets.py +13 -15
  295. meta_screening/admin/list_filters.py +7 -5
  296. meta_screening/admin/screening_part_one_admin.py +1 -3
  297. meta_screening/admin/screening_part_three_admin.py +2 -3
  298. meta_screening/admin/screening_part_two_admin.py +7 -10
  299. meta_screening/admin/subject_refusal_admin.py +5 -3
  300. meta_screening/admin/subject_screening_admin.py +21 -10
  301. meta_screening/baker_recipes.py +18 -10
  302. meta_screening/calculators.py +1 -1
  303. meta_screening/choices.py +1 -1
  304. meta_screening/constants.py +1 -1
  305. meta_screening/eligibility/__init__.py +9 -0
  306. meta_screening/eligibility/eligibility.py +21 -14
  307. meta_screening/eligibility/eligibility_part_one.py +1 -1
  308. meta_screening/eligibility/eligibility_part_three/__init__.py +2 -0
  309. meta_screening/eligibility/eligibility_part_three/base_eligibility_part_three.py +68 -49
  310. meta_screening/eligibility/eligibility_part_three/eligibility_part_three_phase_three.py +14 -15
  311. meta_screening/eligibility/eligibility_part_two.py +1 -1
  312. meta_screening/form_validators/__init__.py +8 -0
  313. meta_screening/form_validators/screening_part_one.py +1 -1
  314. meta_screening/form_validators/screening_part_three.py +6 -2
  315. meta_screening/form_validators/screening_part_two.py +1 -1
  316. meta_screening/form_validators/subject_refusal.py +1 -1
  317. meta_screening/forms/__init__.py +20 -0
  318. meta_screening/forms/field_lists.py +16 -18
  319. meta_screening/forms/screening_part_one_form.py +2 -2
  320. meta_screening/forms/screening_part_three_form.py +5 -3
  321. meta_screening/forms/screening_part_two_form.py +1 -5
  322. meta_screening/forms/subject_refusal_form.py +0 -4
  323. meta_screening/forms/subject_screening_form.py +0 -4
  324. meta_screening/migrations/0001_initial.py +15 -15
  325. meta_screening/migrations/0010_auto_20191106_0828.py +5 -5
  326. meta_screening/migrations/0012_auto_20191107_0427.py +1 -1
  327. meta_screening/migrations/0068_alter_historicalscreeningpartone_acute_condition_and_more.py +1579 -0
  328. meta_screening/model_mixins/__init__.py +8 -0
  329. meta_screening/model_mixins/calculated_model_mixin.py +2 -2
  330. meta_screening/model_mixins/creatinine_fields_model_mixin.py +1 -1
  331. meta_screening/model_mixins/eligibility_model_mixin.py +6 -4
  332. meta_screening/model_mixins/part_one_fields_model_mixin.py +16 -19
  333. meta_screening/model_mixins/part_three_fields_model_mixin.py +6 -7
  334. meta_screening/model_mixins/part_two_fields_model_mixin.py +19 -17
  335. meta_screening/models/__init__.py +9 -0
  336. meta_screening/models/icp_referral.py +5 -5
  337. meta_screening/models/proxy_models.py +1 -1
  338. meta_screening/models/signals.py +10 -11
  339. meta_screening/models/subject_refusal.py +1 -1
  340. meta_screening/models/subject_screening.py +2 -4
  341. meta_subject/action_items.py +18 -14
  342. meta_subject/admin/__init__.py +42 -0
  343. meta_subject/admin/birth_outcome_admin.py +7 -9
  344. meta_subject/admin/blood_results/__init__.py +9 -0
  345. meta_subject/admin/blood_results/blood_results_fbc_admin.py +1 -1
  346. meta_subject/admin/blood_results/blood_results_hba1c_admin.py +1 -1
  347. meta_subject/admin/blood_results/blood_results_ins_admin.py +1 -1
  348. meta_subject/admin/blood_results/blood_results_lft_admin.py +1 -1
  349. meta_subject/admin/blood_results/blood_results_lipids_admin.py +1 -1
  350. meta_subject/admin/blood_results/blood_results_rft_admin.py +3 -5
  351. meta_subject/admin/complications_glycemia_admin.py +1 -1
  352. meta_subject/admin/delivery_admin.py +8 -11
  353. meta_subject/admin/diabetes/__init__.py +2 -0
  354. meta_subject/admin/diabetes/dm_endpoint_admin.py +2 -2
  355. meta_subject/admin/diabetes/dm_followup_admin.py +3 -2
  356. meta_subject/admin/egfr_drop_notification_admin.py +1 -1
  357. meta_subject/admin/fields.py +5 -5
  358. meta_subject/admin/fieldsets.py +5 -5
  359. meta_subject/admin/followup_examination_admin.py +11 -9
  360. meta_subject/admin/followup_vitals_admin.py +31 -6
  361. meta_subject/admin/glucose_admin.py +4 -8
  362. meta_subject/admin/glucose_fbg_admin.py +18 -11
  363. meta_subject/admin/health_economics/__init__.py +2 -0
  364. meta_subject/admin/health_economics/health_economics_simple_admin.py +1 -1
  365. meta_subject/admin/health_economics/health_economics_update_admin.py +1 -1
  366. meta_subject/admin/hepatitis_test_admin.py +1 -1
  367. meta_subject/admin/hiv_exit_review_admin.py +55 -0
  368. meta_subject/admin/list_filters.py +5 -5
  369. meta_subject/admin/mnsi_admin.py +7 -5
  370. meta_subject/admin/next_appointment_admin.py +19 -0
  371. meta_subject/admin/other_arv_regimens_admin.py +3 -3
  372. meta_subject/admin/patient_history_admin.py +4 -4
  373. meta_subject/admin/physical_exam_admin.py +1 -1
  374. meta_subject/admin/pregnancy_update_admin.py +1 -1
  375. meta_subject/admin/study_medication_admin.py +8 -15
  376. meta_subject/admin/subject_requisition_admin.py +2 -2
  377. meta_subject/admin/subject_visit_admin.py +1 -1
  378. meta_subject/admin/subject_visit_missed_admin.py +1 -1
  379. meta_subject/admin/urine_dipstick_test_admin.py +1 -1
  380. meta_subject/admin/urine_pregnancy_admin.py +1 -1
  381. meta_subject/baker_recipes.py +15 -15
  382. meta_subject/choices.py +4 -3
  383. meta_subject/form_validators/__init__.py +15 -0
  384. meta_subject/form_validators/delivery_form_validator.py +3 -3
  385. meta_subject/form_validators/dm_endpoint_form_validator.py +3 -1
  386. meta_subject/form_validators/dm_followup_form_validator.py +8 -7
  387. meta_subject/form_validators/egfr_drop_notification_form_validator.py +1 -1
  388. meta_subject/form_validators/followup_examination_form_validator.py +1 -1
  389. meta_subject/form_validators/glucose_fbg_form_validator.py +76 -0
  390. meta_subject/form_validators/glucose_form_validator.py +10 -67
  391. meta_subject/form_validators/hiv_exit_review_form_validator.py +18 -0
  392. meta_subject/form_validators/mixins.py +95 -0
  393. meta_subject/forms/__init__.py +44 -0
  394. meta_subject/forms/blood_results/__init__.py +9 -0
  395. meta_subject/forms/blood_results/blood_results_hba1c_form.py +1 -1
  396. meta_subject/forms/blood_results/blood_results_rft_form.py +60 -4
  397. meta_subject/forms/delivery_form.py +2 -0
  398. meta_subject/forms/diabetes/__init__.py +2 -0
  399. meta_subject/forms/diabetes/dm_followup_form.py +2 -2
  400. meta_subject/forms/followup_vitals_form.py +27 -1
  401. meta_subject/forms/glucose_fbg_form.py +1 -46
  402. meta_subject/forms/health_economics/__init__.py +2 -0
  403. meta_subject/forms/hepatitis_test_form.py +1 -1
  404. meta_subject/forms/hiv_exit_review_form.py +13 -0
  405. meta_subject/forms/mixins.py +1 -1
  406. meta_subject/forms/next_appointment_form.py +36 -0
  407. meta_subject/forms/other_arv_regimens_form.py +1 -1
  408. meta_subject/forms/patient_history_form.py +1 -1
  409. meta_subject/forms/physical_exam_form.py +1 -1
  410. meta_subject/forms/pregnancy_update_form.py +1 -1
  411. meta_subject/forms/slider_widget.py +1 -1
  412. meta_subject/forms/study_medication_form.py +18 -12
  413. meta_subject/forms/subject_requisition_form.py +1 -1
  414. meta_subject/forms/subject_visit_missed_form.py +1 -1
  415. meta_subject/forms/urine_dipstick_test_form.py +1 -1
  416. meta_subject/forms/urine_pregnancy_form.py +1 -1
  417. meta_subject/management/commands/create_missing_refills.py +3 -3
  418. meta_subject/management/commands/create_missing_rx.py +2 -2
  419. meta_subject/management/commands/missed.py +20 -23
  420. meta_subject/metadata_rules/__init__.py +2 -0
  421. meta_subject/metadata_rules/metadata_rules.py +14 -0
  422. meta_subject/metadata_rules/predicates.py +44 -25
  423. meta_subject/migrations/0001_initial.py +61 -61
  424. meta_subject/migrations/0002_auto_20191021_0353.py +5 -5
  425. meta_subject/migrations/0012_auto_20200118_2334.py +5 -5
  426. meta_subject/migrations/0014_auto_20200120_1622.py +5 -5
  427. meta_subject/migrations/0018_coronakap_historicalcoronakap.py +5 -5
  428. meta_subject/migrations/0033_auto_20200516_2356.py +5 -5
  429. meta_subject/migrations/0038_auto_20200520_0020.py +5 -5
  430. meta_subject/migrations/0040_auto_20200527_2155.py +1 -1
  431. meta_subject/migrations/0045_auto_20200530_1801.py +1 -1
  432. meta_subject/migrations/0051_auto_20200617_2117.py +5 -5
  433. meta_subject/migrations/0063_auto_20210715_0337.py +5 -5
  434. meta_subject/migrations/0066_auto_20210721_0335.py +9 -9
  435. meta_subject/migrations/0067_auto_20210726_0340.py +5 -5
  436. meta_subject/migrations/0068_auto_20210728_1809.py +5 -5
  437. meta_subject/migrations/0072_auto_20210805_1545.py +7 -7
  438. meta_subject/migrations/0073_auto_20210809_0055.py +5 -5
  439. meta_subject/migrations/0077_auto_20210809_2323.py +3 -3
  440. meta_subject/migrations/0082_auto_20210823_1612.py +3 -3
  441. meta_subject/migrations/0083_auto_20210823_1620.py +3 -3
  442. meta_subject/migrations/0088_auto_20210924_0027.py +5 -5
  443. meta_subject/migrations/0090_auto_20210924_0424.py +5 -5
  444. meta_subject/migrations/0093_auto_20211117_0352.py +5 -5
  445. meta_subject/migrations/0095_auto_20220128_1719.py +5 -5
  446. meta_subject/migrations/0098_auto_20220309_2106.py +5 -5
  447. meta_subject/migrations/0101_auto_20220316_2147.py +13 -13
  448. meta_subject/migrations/0107_auto_20220415_0043.py +1 -1
  449. meta_subject/migrations/0115_historicalegfrnotification_egfrnotification.py +5 -13
  450. meta_subject/migrations/0128_auto_20220720_0055.py +1 -1
  451. meta_subject/migrations/0131_auto_20220722_0411.py +1 -1
  452. meta_subject/migrations/0135_auto_20220722_2212.py +2 -1
  453. meta_subject/migrations/0164_dmreferralfollowup_historicaldmreferralfollowup.py +5 -5
  454. meta_subject/migrations/0172_remove_historicalbloodresultsglu_action_item_and_more.py +1 -2
  455. meta_subject/migrations/0177_alter_bloodresultslft_alp_value_and_more.py +1 -2
  456. meta_subject/migrations/0178_historicalhealtheconomicsupdate_and_more.py +5 -14
  457. meta_subject/migrations/0186_healtheconomicsupdate_singleton_field_and_more.py +1 -2
  458. meta_subject/migrations/0187_dmdiagnosis_historicaldmdiagnosis_dmdxresult_and_more.py +5 -14
  459. meta_subject/migrations/0188_historicaldmdxresult_dmdxresult.py +5 -14
  460. meta_subject/migrations/0199_auto_20240516_0247.py +1 -1
  461. meta_subject/migrations/0209_remove_historicaldmdxresult_dm_diagnosis_and_more.py +1 -2
  462. meta_subject/migrations/0212_auto_20240827_2222.py +1 -1
  463. meta_subject/migrations/0216_historicalnextappointment_nextappointment.py +553 -0
  464. meta_subject/migrations/0217_alter_historicalnextappointment_appt_datetime_and_more.py +42 -0
  465. meta_subject/migrations/0218_alter_historicalnextappointment_appt_date_and_more.py +53 -0
  466. meta_subject/migrations/0219_remove_historicalnextappointment_allow_create_interim_and_more.py +92 -0
  467. meta_subject/migrations/0220_historicalbloodresultsgludummy_bloodresultsgludummy.py +825 -0
  468. meta_subject/migrations/0221_auto_20250402_1913.py +42 -0
  469. meta_subject/migrations/0222_alter_historicalstudymedication_stock_codes_and_more.py +46 -0
  470. meta_subject/migrations/0223_bloodresultsfbc_errors_bloodresultsgludummy_errors_and_more.py +83 -0
  471. meta_subject/migrations/0224_bloodresultsfbc_abnormal_summary_and_more.py +153 -0
  472. meta_subject/migrations/0225_followupvitals_waist_circumference_and_more.py +46 -0
  473. meta_subject/migrations/0226_followupvitals_waist_circumference_comment_and_more.py +97 -0
  474. meta_subject/migrations/0227_alter_followupvitals_waist_circumference_comment_and_more.py +97 -0
  475. meta_subject/migrations/0228_bloodresultshba1c_hba1c_datetime_and_more.py +2518 -0
  476. meta_subject/migrations/0229_alter_glucosefbg_consent_model_and_more.py +1918 -0
  477. meta_subject/migrations/0230_alter_historicaldelivery_action_identifier_and_more.py +1733 -0
  478. meta_subject/migrations/0231_alter_historicalmedicationadherence_consent_model_and_more.py +2054 -0
  479. meta_subject/migrations/0232_alter_patienthistory_concomitant_conditions_and_more.py +1170 -0
  480. meta_subject/migrations/0233_historicalspfq_spfq.py +1066 -0
  481. meta_subject/migrations/0234_remove_spfq_site_remove_spfq_subject_visit_and_more.py +27 -0
  482. meta_subject/migrations/0235_glucosefbg_endpoint_today_and_more.py +606 -0
  483. meta_subject/migrations/0236_alter_historicalhivexitreview_other_current_arv_regimen_and_more.py +58 -0
  484. meta_subject/migrations/0237_historicalhivexitreview_singleton_field_and_more.py +68 -0
  485. meta_subject/migrations/0238_historicalhivexitreview_available_and_more.py +88 -0
  486. meta_subject/model_mixins/__init__.py +10 -0
  487. meta_subject/model_mixins/arv_history_model_mixin.py +3 -44
  488. meta_subject/model_mixins/arv_review_model_mixin.py +53 -0
  489. meta_subject/model_mixins/search_slug_model_mixin.py +1 -2
  490. meta_subject/model_mixins/vitals_fields_model_mixin.py +33 -0
  491. meta_subject/models/__init__.py +52 -0
  492. meta_subject/models/birth_outcomes.py +3 -3
  493. meta_subject/models/blood_results/__init__.py +11 -0
  494. meta_subject/models/blood_results/blood_results_glu.py +29 -0
  495. meta_subject/models/blood_results/blood_results_hba1c.py +0 -1
  496. meta_subject/models/blood_results/blood_results_ins.py +0 -1
  497. meta_subject/models/blood_results/blood_results_lft.py +0 -1
  498. meta_subject/models/delivery.py +4 -6
  499. meta_subject/models/diabetes/__init__.py +2 -0
  500. meta_subject/models/diabetes/dm_endpoint.py +5 -5
  501. meta_subject/models/diabetes/dm_followup.py +7 -8
  502. meta_subject/models/diet_and_lifestyle.py +2 -2
  503. meta_subject/models/followup_examination.py +12 -14
  504. meta_subject/models/glucose.py +5 -5
  505. meta_subject/models/glucose_fbg.py +17 -4
  506. meta_subject/models/health_economics/__init__.py +2 -0
  507. meta_subject/models/health_economics/health_economics.py +8 -8
  508. meta_subject/models/health_economics/health_economics_simple.py +2 -2
  509. meta_subject/models/health_economics/health_economics_update.py +3 -2
  510. meta_subject/models/hepatitis_test.py +2 -2
  511. meta_subject/models/hiv_exit_review.py +44 -0
  512. meta_subject/models/next_appointment.py +15 -0
  513. meta_subject/models/other_arv_regimens_detail.py +1 -1
  514. meta_subject/models/patient_history.py +6 -7
  515. meta_subject/models/physical_exam.py +2 -2
  516. meta_subject/models/pregnancy_update.py +1 -1
  517. meta_subject/models/signals.py +15 -13
  518. meta_subject/models/subject_visit.py +2 -2
  519. meta_subject/models/todo.txt +1 -1
  520. meta_subject/models/urine_dipstick_test.py +2 -2
  521. meta_subject/models/urine_pregnancy.py +1 -1
  522. meta_subject/static/meta_subject/slider.css +1 -1
  523. meta_subject/templates/meta_subject/endpoint_review_instructions.html +1 -1
  524. meta_subject/templates/meta_subject/widgets/slider.html +0 -1
  525. meta_visit_schedule/visit_schedules/__init__.py +2 -0
  526. meta_visit_schedule/visit_schedules/phase_three/__init__.py +2 -0
  527. meta_visit_schedule/visit_schedules/phase_three/crfs.py +34 -1
  528. meta_visit_schedule/visit_schedules/phase_three/schedule.py +4 -4
  529. meta_visit_schedule/visit_schedules/phase_three/schedule_dm_referral.py +1 -2
  530. meta_visit_schedule/visit_schedules/phase_three/schedule_pregnancy.py +2 -3
  531. meta_ae/tests/holidays.csv +0 -15
  532. meta_ae/tests/tests/test_actions.py +0 -127
  533. meta_ae/tests/urls.py +0 -10
  534. meta_analytics/dataframes/enrolled/__init__.py +0 -1
  535. meta_analytics/dataframes/enrolled/get_glucose_df.py +0 -122
  536. meta_analytics/tests/__init__.py +0 -0
  537. meta_analytics/tests/test_endpoints_by_date.py +0 -94
  538. meta_consent/tests/__init__.py +0 -0
  539. meta_consent/tests/holidays.csv +0 -15
  540. meta_consent/tests/tests/__init__.py +0 -0
  541. meta_consent/tests/tests/test_form_validators.py +0 -110
  542. meta_consent/tests/tests/test_subject_consent.py +0 -10
  543. meta_consent/tests/urls.py +0 -17
  544. meta_dashboard/templates/meta_dashboard/bootstrap3/subject/dashboard.html +0 -11
  545. meta_dashboard/tests/__init__.py +0 -0
  546. meta_dashboard/tests/admin.py +0 -22
  547. meta_dashboard/tests/holidays.csv +0 -15
  548. meta_dashboard/tests/tests/__init__.py +0 -0
  549. meta_dashboard/tests/urls.py +0 -55
  550. meta_edc/tests/__init__.py +0 -0
  551. meta_edc/tests/tests/__init__.py +0 -0
  552. meta_edc/tests/tests/test_endpoints.py +0 -554
  553. meta_edc-0.3.39.dist-info/AUTHORS +0 -0
  554. meta_edc-0.3.39.dist-info/METADATA +0 -766
  555. meta_edc-0.3.39.dist-info/WHEEL +0 -5
  556. meta_edc-0.3.39.dist-info/top_level.txt +0 -20
  557. meta_labs/tests/__init__.py +0 -0
  558. meta_labs/tests/test_labs.py +0 -27
  559. meta_labs/tests/test_reportables.py +0 -16
  560. meta_labs/tests/urls.py +0 -4
  561. meta_lists/tests/__init__.py +0 -0
  562. meta_lists/tests/test_lists.py +0 -8
  563. meta_pharmacy/admin/actions.py +0 -38
  564. meta_prn/tests/__init__.py +0 -0
  565. meta_prn/tests/tests/__init__.py +0 -0
  566. meta_prn/tests/tests/test_actions.py +0 -97
  567. meta_prn/tests/tests/test_dm_referral.py +0 -206
  568. meta_prn/tests/tests/test_manager_order.py +0 -14
  569. meta_prn/tests/tests/test_pregnancy_notification.py +0 -93
  570. meta_prn/tests/urls.py +0 -10
  571. meta_rando/tests/__init__.py +0 -0
  572. meta_rando/tests/tests/__init__.py +0 -0
  573. meta_rando/tests/tests/test_randomizers.py +0 -57
  574. meta_reports/tests/__init__.py +0 -0
  575. meta_reports/tests/test_reports.py +0 -35
  576. meta_reports/tests/test_sql_gen.py +0 -5
  577. meta_reports/tests/urls.py +0 -4
  578. meta_screening/offline_models.py +0 -3
  579. meta_screening/tests/__init__.py +0 -0
  580. meta_screening/tests/holidays.csv +0 -15
  581. meta_screening/tests/meta_test_case_mixin.py +0 -216
  582. meta_screening/tests/options.py +0 -127
  583. meta_screening/tests/tests/__init__.py +0 -0
  584. meta_screening/tests/tests/test_forms.py +0 -397
  585. meta_screening/tests/tests/test_screening_part_one.py +0 -108
  586. meta_screening/tests/tests/test_screening_part_three.py +0 -436
  587. meta_screening/tests/tests/test_screening_part_two.py +0 -84
  588. meta_sites/tests/__init__.py +0 -0
  589. meta_sites/tests/test_sites.py +0 -12
  590. meta_sites/tests/urls.py +0 -4
  591. meta_stats/__init__.py +0 -0
  592. meta_stats/incidence.py +0 -16
  593. meta_stats/models.py +0 -0
  594. meta_stats/tests/__init__.py +0 -0
  595. meta_stats/tests/tests/__init__.py +0 -0
  596. meta_stats/tests/tests/test_incidence.py +0 -10
  597. meta_subject/tests/__init__.py +0 -0
  598. meta_subject/tests/holidays.csv +0 -15
  599. meta_subject/tests/tests/__init__.py +0 -0
  600. meta_subject/tests/tests/test_egfr.py +0 -234
  601. meta_subject/tests/tests/test_fixes.py +0 -64
  602. meta_subject/tests/tests/test_followup.py +0 -52
  603. meta_subject/tests/tests/test_manager_order.py +0 -11
  604. meta_subject/tests/tests/test_medication_adherence.py +0 -75
  605. meta_subject/tests/tests/test_metadata_rules.py +0 -135
  606. meta_subject/tests/tests/test_mnsi.py +0 -317
  607. meta_subject/tests/tests/test_patient_history_form.py +0 -74
  608. meta_subject/tests/tests/test_physical_exam.py +0 -84
  609. meta_subject/tests/tests/test_sf12.py +0 -173
  610. meta_subject/tests/tests/test_study_medication.py +0 -230
  611. meta_subject/tests/urls.py +0 -24
  612. meta_visit_schedule/tests/__init__.py +0 -0
  613. meta_visit_schedule/tests/tests/__init__.py +0 -0
  614. meta_visit_schedule/tests/tests/test_schedule.py +0 -181
  615. meta_visit_schedule/tests/urls.py +0 -4
  616. tests/__init__.py +0 -0
  617. tests/etc/randomization_list.csv +0 -241
  618. tests/etc/randomization_list_phase_three.csv +0 -241
  619. tests/etc/user-aes-local.key +0 -0
  620. tests/etc/user-aes-restricted.key +0 -1
  621. tests/etc/user-rsa-local-private.pem +0 -27
  622. tests/etc/user-rsa-local-public.pem +0 -9
  623. tests/etc/user-rsa-restricted-private.pem +0 -27
  624. tests/etc/user-rsa-restricted-public.pem +0 -9
  625. tests/etc/user-salt-local.key +0 -0
  626. tests/etc/user-salt-restricted.key +0 -0
  627. tests/holidays.csv +0 -15
  628. tests/test_settings.py +0 -186
  629. /meta_ae/templates/meta_ae/{bootstrap3/ae_initial_description.html → aeinitial_description.html} +0 -0
  630. /meta_dashboard/templates/meta_dashboard/{bootstrap3/buttons → buttons}/add_consent_button.html +0 -0
  631. /meta_dashboard/templates/meta_dashboard/{bootstrap3/buttons → buttons}/dashboard_button.html +0 -0
  632. /meta_dashboard/templates/meta_dashboard/{bootstrap3/buttons → buttons}/refusal_button.html +0 -0
  633. /meta_dashboard/templates/meta_dashboard/{bootstrap3/screening → screening}/listboard.html +0 -0
  634. /meta_dashboard/templates/meta_dashboard/{bootstrap3/subject → subject}/listboard.html +0 -0
  635. {meta_edc-0.3.39.dist-info → meta_edc-1.4.0.dist-info/licenses}/LICENSE +0 -0
  636. /meta_ae/tests/__init__.py → /meta_subject/management/__init__py.py +0 -0
  637. /meta_ae/tests/tests/__init__.py → /meta_subject/management/commands/__init__py.py +0 -0
@@ -1,4 +1,14 @@
1
1
  from .signals import subject_consent_on_post_delete, subject_consent_on_post_save
2
2
  from .subject_consent import SubjectConsent
3
3
  from .subject_consent_v1 import SubjectConsentV1
4
+ from .subject_consent_v1_ext import SubjectConsentV1Ext
4
5
  from .subject_reconsent import SubjectReconsent
6
+
7
+ __all__ = [
8
+ "SubjectConsent",
9
+ "SubjectConsentV1",
10
+ "SubjectConsentV1Ext",
11
+ "SubjectReconsent",
12
+ "subject_consent_on_post_delete",
13
+ "subject_consent_on_post_save",
14
+ ]
@@ -4,8 +4,7 @@ from edc_search.model_mixins import SearchSlugModelMixin as Base
4
4
  class SearchSlugModelMixin(Base):
5
5
  def get_search_slug_fields(self):
6
6
  fields = super().get_search_slug_fields()
7
- fields.append("subject_identifier")
8
- return fields
7
+ return *fields, "subject_identifier"
9
8
 
10
9
  class Meta:
11
10
  abstract = True
@@ -1,8 +1,10 @@
1
+ import contextlib
2
+
3
+ from clinicedc_constants import YES
1
4
  from django.core.exceptions import ValidationError
2
5
  from django.db.models.signals import post_delete, post_save
3
6
  from django.dispatch import receiver
4
- from edc_action_item import ActionItemDeleteError, delete_action_item
5
- from edc_constants.constants import YES
7
+ from edc_action_item.delete_action_item import ActionItemDeleteError, delete_action_item
6
8
  from edc_pharmacy.exceptions import PrescriptionAlreadyExists
7
9
  from edc_pharmacy.prescribe import create_prescription
8
10
  from edc_randomization.site_randomizers import site_randomizers
@@ -23,10 +25,11 @@ from .subject_consent_v1 import SubjectConsentV1
23
25
  sender=SubjectConsentV1,
24
26
  dispatch_uid="subject_consent_on_post_save",
25
27
  )
26
- def subject_consent_on_post_save(sender, instance, raw, created, **kwargs):
28
+ def subject_consent_on_post_save(sender, instance, raw, created, **kwargs): # noqa: ARG001
27
29
  """Creates an onschedule instance for this consented subject, if
28
30
  it does not exist.
29
31
  """
32
+
30
33
  if not raw:
31
34
  if not created:
32
35
  _, schedule = site_visit_schedules.get_by_onschedule_model("meta_prn.onschedule")
@@ -59,28 +62,39 @@ def subject_consent_on_post_save(sender, instance, raw, created, **kwargs):
59
62
  onschedule_datetime=instance.consent_datetime,
60
63
  )
61
64
  # All refills are created against this prescription
62
- try:
65
+ with contextlib.suppress(PrescriptionAlreadyExists):
63
66
  create_prescription(
64
67
  subject_identifier=instance.subject_identifier,
65
68
  report_datetime=instance.consent_datetime,
66
- medications=[instance.study_medication_name],
69
+ medication_names=[instance.study_medication_name],
67
70
  randomizer_name=get_meta_version(),
68
71
  site=instance.site,
69
72
  )
70
- except PrescriptionAlreadyExists:
71
- pass
72
73
 
73
74
  # create / delete action for reconsent
74
75
  if instance.completed_by_next_of_kin == YES:
75
76
  ReconsentAction(subject_identifier=instance.subject_identifier)
76
77
  else:
77
- try:
78
+ with contextlib.suppress(ActionItemDeleteError):
78
79
  delete_action_item(
79
80
  action_cls=ReconsentAction,
80
81
  subject_identifier=instance.subject_identifier,
81
82
  )
82
- except ActionItemDeleteError:
83
- pass
83
+
84
+
85
+ # @receiver(
86
+ # post_save,
87
+ # weak=False,
88
+ # sender=SubjectConsentV1Ext,
89
+ # dispatch_uid="subject_consent_v1_ext_on_post_save",
90
+ # )
91
+ # def subject_consent_v1_ext_on_post_save(sender, instance, raw, created, **kwargs):
92
+ # if not raw:
93
+ # refresh_appointments(
94
+ # subject_identifier=instance.subject_identifier,
95
+ # visit_schedule_name=VISIT_SCHEDULE,
96
+ # schedule_name=SCHEDULE,
97
+ # )
84
98
 
85
99
 
86
100
  @receiver(
@@ -88,7 +102,7 @@ def subject_consent_on_post_save(sender, instance, raw, created, **kwargs):
88
102
  weak=False,
89
103
  dispatch_uid="subject_consent_on_post_delete",
90
104
  )
91
- def subject_consent_on_post_delete(sender, instance, using, **kwargs):
105
+ def subject_consent_on_post_delete(sender, instance, using, **kwargs): # noqa: ARG001
92
106
  """Updates/Resets subject screening."""
93
107
  # don't allow if subject visits exist. This should be caught
94
108
  # in the ModelAdmin delete view
@@ -1,3 +1,4 @@
1
+ from clinicedc_constants import NO, NOT_APPLICABLE
1
2
  from django.apps import apps as django_apps
2
3
  from django.contrib.sites.managers import CurrentSiteManager
3
4
  from django.db import models
@@ -13,7 +14,6 @@ from edc_consent.field_mixins import (
13
14
  from edc_consent.managers import ConsentObjectsManager
14
15
  from edc_consent.model_mixins import ConsentModelMixin
15
16
  from edc_constants.choices import YES_NO
16
- from edc_constants.constants import NO, NOT_APPLICABLE
17
17
  from edc_identifier.model_mixins import NonUniqueSubjectIdentifierModelMixin
18
18
  from edc_identifier.subject_identifier import SubjectIdentifier as BaseSubjectIdentifier
19
19
  from edc_model.models import BaseUuidModel, HistoricalRecords
@@ -62,7 +62,7 @@ class SubjectConsent(
62
62
  max_length=15,
63
63
  help_text=_("from screening"),
64
64
  editable=False,
65
- null=True,
65
+ default="",
66
66
  )
67
67
 
68
68
  completed_by_next_of_kin = models.CharField(
@@ -5,7 +5,6 @@ from .subject_consent import SubjectConsent
5
5
 
6
6
 
7
7
  class SubjectConsentV1(SubjectConsent):
8
-
9
8
  objects = ConsentObjectsByCdefManager()
10
9
  on_site = CurrentSiteByCdefManager()
11
10
  history = HistoricalRecords()
@@ -0,0 +1,34 @@
1
+ from django.db import models
2
+ from edc_action_item.models import ActionModelMixin
3
+ from edc_consent.field_mixins import ReviewFieldsMixin
4
+ from edc_consent.model_mixins import ConsentExtensionModelMixin
5
+ from edc_model.models import BaseUuidModel
6
+ from edc_sites.model_mixins import SiteModelMixin
7
+
8
+ from ..constants import CONSENT_V1_EXTENSION_ACTION
9
+ from .subject_consent_v1 import SubjectConsentV1
10
+
11
+
12
+ class SubjectConsentV1Ext(
13
+ ConsentExtensionModelMixin,
14
+ SiteModelMixin,
15
+ ActionModelMixin,
16
+ ReviewFieldsMixin,
17
+ BaseUuidModel,
18
+ ):
19
+ """A consent extension to allow a participant to extend followup
20
+ up to 48 months, or not.
21
+ """
22
+
23
+ subject_consent = models.ForeignKey(SubjectConsentV1, on_delete=models.PROTECT)
24
+
25
+ action_name = CONSENT_V1_EXTENSION_ACTION
26
+
27
+ class Meta(
28
+ ConsentExtensionModelMixin.Meta,
29
+ SiteModelMixin.Meta,
30
+ ActionModelMixin.Meta,
31
+ BaseUuidModel.Meta,
32
+ ):
33
+ verbose_name = "Consent V1 Extension"
34
+ verbose_name_plural = "Consent V1 Extension"
@@ -1,3 +1,4 @@
1
+ from clinicedc_constants import ABNORMAL
1
2
  from django.apps import apps as django_apps
2
3
  from django.contrib.sites.managers import CurrentSiteManager
3
4
  from django.contrib.sites.models import Site
@@ -6,7 +7,6 @@ from django.db import models
6
7
  from django_crypto_fields.fields.identity_field import IdentityField
7
8
  from edc_action_item.models import ActionModelMixin
8
9
  from edc_consent.field_mixins import ReviewFieldsMixin
9
- from edc_constants.constants import ABNORMAL
10
10
  from edc_identifier.managers import SubjectIdentifierManager
11
11
  from edc_identifier.model_mixins import UniqueSubjectIdentifierModelMixin
12
12
  from edc_model.models import BaseUuidModel
@@ -67,12 +67,12 @@ class SubjectReconsent(
67
67
  self.get_subject_consent(
68
68
  screening_identifier=subject_screening.screening_identifier
69
69
  )
70
- except ObjectDoesNotExist:
71
- raise ValidationError("Previous consent does not exist.")
70
+ except ObjectDoesNotExist as e:
71
+ raise ValidationError("Previous consent does not exist.") from e
72
72
  super().save(*args, **kwargs)
73
73
 
74
74
  def natural_key(self):
75
- return (self.subject_identifier, self.version)
75
+ return self.subject_identifier, self.version
76
76
 
77
77
  def get_subject_consent(self, screening_identifier=None):
78
78
  """Returns the first subject consent model instance."""
meta_dashboard/navbars.py CHANGED
@@ -4,8 +4,6 @@ from edc_navbar import Navbar, NavbarItem, site_navbars
4
4
  from edc_pharmacy.navbars import pharmacy_navbar_item
5
5
  from edc_review_dashboard.navbars import navbar_item as review_navbar_item
6
6
 
7
- no_url_namespace = False # True if settings.APP_NAME == "meta_dashboard" else False
8
-
9
7
  navbar = Navbar(name="meta_dashboard")
10
8
 
11
9
 
@@ -16,8 +14,7 @@ navbar.register(
16
14
  label="Screening",
17
15
  fa_icon="fa-user-plus",
18
16
  codename="edc_screening.view_screening_listboard",
19
- url_name="screening_listboard_url",
20
- no_url_namespace=no_url_namespace,
17
+ url_names_key="screening_listboard_url",
21
18
  )
22
19
  )
23
20
 
@@ -28,8 +25,7 @@ navbar.register(
28
25
  label="Subjects",
29
26
  fa_icon="fa-user-circle",
30
27
  codename="edc_subject_dashboard.view_subject_listboard",
31
- url_name="subject_listboard_url",
32
- no_url_namespace=no_url_namespace,
28
+ url_names_key="subject_listboard_url",
33
29
  )
34
30
  )
35
31
 
@@ -1 +1 @@
1
- screening_identifier = "[A-Z0-9]{6,8}" # noqa
1
+ screening_identifier = "[A-Z0-9]{6,8}"
@@ -12,4 +12,4 @@
12
12
  </ul>
13
13
  {% endif %}
14
14
  </div>
15
- {% endif %}
15
+ {% endif %}
@@ -12,4 +12,4 @@
12
12
  class="btn btn-sm btn-{% if p3 == YES %}success{% elif p1 == YES and p2 == YES and p3 == TBD %}warning{% else %}default{% endif %}"
13
13
  {% if p3_enabled %}href="{{ href_p3 }}"{% else %} disabled {% endif %}>
14
14
  <i class="fas fa-pencil-alt fa-sm"></i> P3
15
- </a>
15
+ </a>
@@ -0,0 +1,24 @@
1
+ {% extends 'edc_subject_dashboard/dashboard/sidebar.html' %}
2
+ {% load edc_subject_dashboard_extras %}
3
+
4
+ {% block consents %}
5
+ {{ block.super }}
6
+ {% if subject_consent_v1_ext %}
7
+ <table class="table table-condensed">
8
+ <thead></thead>
9
+ <tbody>
10
+ <tr>
11
+ <td class="{% if subject_consent_v1_ext %}default{% else %}warning{% endif %}">
12
+ {% render_subject_consent_dashboard_button subject_consent_v1_ext appointment %}
13
+ </td>
14
+ <td class="{% if subject_consent_v1_ext %}default{% else %}warning{% endif %}">
15
+ <span class="h6">{{ subject_consent_v1_ext.verbose_name|title }}&nbsp;<span class="text {% if subject_consent_v1_ext.agrees_to_extension == YES %}text-success{% else %}text-danger{% endif %}">{{ subject_consent_v1_ext.agrees_to_extension }}</span>
16
+ <span class="text text-muted">{{ subject_consent_v1_ext.report_datetime|date:"SHORT_DATE_FORMAT"}}</span>
17
+ </span>
18
+ </td>
19
+ </tr>
20
+ </tbody>
21
+ </table>
22
+ {% endif %}
23
+
24
+ {% endblock consents %}
@@ -1,3 +1,3 @@
1
- {% extends 'edc_subject_dashboard/bootstrap3/dashboard/topbar.html' %}
1
+ {% extends 'edc_subject_dashboard/dashboard/topbar.html' %}
2
2
 
3
3
  {% block close_url %}href="{% url subject_listboard_url|default:'subject_listboard_url_cannot_be_none' %}?q={{ subject_identifier }}"{% endblock close_url %}
@@ -0,0 +1,14 @@
1
+ {% extends 'edc_subject_dashboard/dashboard.html' %}
2
+
3
+ {% load static %}
4
+
5
+ {% block locator_information %}{% endblock locator_information %}
6
+
7
+ {% block top_bar %}
8
+
9
+ {% include "meta_dashboard/subject/dashboard/top_bar.html" %}
10
+
11
+ {% endblock top_bar %}
12
+
13
+
14
+ {% block side_bar %}{% include 'meta_dashboard/subject/dashboard/sidebar.html' %}{% endblock side_bar %}
@@ -3,13 +3,12 @@ from __future__ import annotations
3
3
  from typing import TYPE_CHECKING
4
4
 
5
5
  from bs4 import BeautifulSoup
6
+ from clinicedc_constants import TBD
6
7
  from django import template
7
- from edc_constants.constants import TBD
8
8
  from edc_dashboard.url_names import url_names
9
- from edc_dashboard.utils import get_bootstrap_version
10
9
 
11
10
  from meta_consent.models import SubjectConsent
12
- from meta_dashboard.view_utils.subject_screening_button import (
11
+ from meta_dashboard.view_utils import (
13
12
  SubjectScreeningPartOneButton,
14
13
  SubjectScreeningPartThreeButton,
15
14
  SubjectScreeningPartTwoButton,
@@ -29,9 +28,7 @@ if TYPE_CHECKING:
29
28
  register = template.Library()
30
29
 
31
30
 
32
- @register.inclusion_tag(
33
- f"meta_dashboard/bootstrap{get_bootstrap_version()}/" f"buttons/eligibility_button.html"
34
- )
31
+ @register.inclusion_tag("meta_dashboard/buttons/eligibility_button.html")
35
32
  def eligibility_button(subject_screening: SubjectScreening):
36
33
  comment = []
37
34
  tooltip = None
@@ -52,7 +49,7 @@ def eligibility_button(subject_screening: SubjectScreening):
52
49
 
53
50
 
54
51
  @register.inclusion_tag(
55
- f"meta_dashboard/bootstrap{get_bootstrap_version()}/buttons/add_consent_button.html",
52
+ "meta_dashboard/buttons/add_consent_button.html",
56
53
  takes_context=True,
57
54
  )
58
55
  def render_consent_button(context, subject_screening: SubjectScreening):
@@ -67,7 +64,7 @@ def render_consent_button(context, subject_screening: SubjectScreening):
67
64
  )
68
65
 
69
66
 
70
- def refusal_button(context, subject_refusal):
67
+ def refusal_button(context, subject_refusal): # noqa: ARG001
71
68
  title = ["Capture subject's primary reason for not joining."]
72
69
 
73
70
  return dict(
@@ -77,9 +74,7 @@ def refusal_button(context, subject_refusal):
77
74
  )
78
75
 
79
76
 
80
- @register.inclusion_tag(
81
- f"edc_listboard/bootstrap{get_bootstrap_version()}/buttons/dashboard_button.html"
82
- )
77
+ @register.inclusion_tag("edc_listboard/buttons/dashboard_button.html")
83
78
  def render_dashboard_button(subject_consent: SubjectConsent):
84
79
  subject_dashboard_url = url_names.get("subject_dashboard_url")
85
80
  return dict(
@@ -89,7 +84,7 @@ def render_dashboard_button(subject_consent: SubjectConsent):
89
84
 
90
85
 
91
86
  @register.inclusion_tag(
92
- f"edc_subject_dashboard/bootstrap{get_bootstrap_version()}/buttons/forms_button.html",
87
+ "edc_subject_dashboard/buttons/forms_button.html",
93
88
  takes_context=True,
94
89
  )
95
90
  def render_screening_part_one_button(context, subject_screening: ScreeningPartOne) -> dict:
@@ -102,7 +97,7 @@ def render_screening_part_one_button(context, subject_screening: ScreeningPartOn
102
97
 
103
98
 
104
99
  @register.inclusion_tag(
105
- f"edc_subject_dashboard/bootstrap{get_bootstrap_version()}/buttons/forms_button.html",
100
+ "edc_subject_dashboard/buttons/forms_button.html",
106
101
  takes_context=True,
107
102
  )
108
103
  def render_screening_part_two_button(context, subject_screening: ScreeningPartTwo) -> dict:
@@ -115,7 +110,7 @@ def render_screening_part_two_button(context, subject_screening: ScreeningPartTw
115
110
 
116
111
 
117
112
  @register.inclusion_tag(
118
- f"edc_subject_dashboard/bootstrap{get_bootstrap_version()}/buttons/forms_button.html",
113
+ "edc_subject_dashboard/buttons/forms_button.html",
119
114
  takes_context=True,
120
115
  )
121
116
  def render_screening_part_three_button(context, subject_screening: ScreeningPartThree) -> dict:
meta_dashboard/urls.py CHANGED
@@ -13,28 +13,28 @@ app_name = "meta_dashboard"
13
13
 
14
14
  urlpatterns = SubjectListboardView.urls(
15
15
  namespace=app_name,
16
- label="subject_listboard",
16
+ url_names_key="subject_listboard_url",
17
17
  identifier_pattern=ResearchProtocolConfig().subject_identifier_pattern,
18
18
  )
19
19
  urlpatterns += ScreeningListboardView.urls(
20
20
  namespace=app_name,
21
- label="screening_listboard",
21
+ url_names_key="screening_listboard_url",
22
22
  identifier_label="screening_identifier",
23
23
  identifier_pattern=screening_identifier,
24
24
  )
25
25
  urlpatterns += SubjectDashboardView.urls(
26
26
  namespace=app_name,
27
- label="subject_dashboard",
27
+ url_names_key="subject_dashboard_url",
28
28
  identifier_pattern=ResearchProtocolConfig().subject_identifier_pattern,
29
29
  )
30
30
 
31
31
  urlpatterns += AeListboardView.urls(
32
32
  namespace=app_name,
33
- label="ae_listboard",
33
+ url_names_key="ae_listboard_url",
34
34
  identifier_pattern=ResearchProtocolConfig().subject_identifier_pattern,
35
35
  )
36
36
  urlpatterns += DeathReportListboardView.urls(
37
37
  namespace=app_name,
38
- label="death_report_listboard",
38
+ url_names_key="death_report_listboard_url",
39
39
  identifier_pattern=ResearchProtocolConfig().subject_identifier_pattern,
40
40
  )
@@ -0,0 +1,13 @@
1
+ from .subject_screening_button import (
2
+ SubjectScreeningButton,
3
+ SubjectScreeningPartOneButton,
4
+ SubjectScreeningPartThreeButton,
5
+ SubjectScreeningPartTwoButton,
6
+ )
7
+
8
+ __all__ = [
9
+ "SubjectScreeningButton",
10
+ "SubjectScreeningPartOneButton",
11
+ "SubjectScreeningPartThreeButton",
12
+ "SubjectScreeningPartTwoButton",
13
+ ]
@@ -1,10 +1,9 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from dataclasses import dataclass, field
4
- from typing import Type
5
4
 
5
+ from clinicedc_constants import TBD, YES
6
6
  from django.utils.translation import gettext as _
7
- from edc_constants.constants import TBD, YES
8
7
  from edc_subject_dashboard.view_utils import (
9
8
  SubjectScreeningButton as BaseSubjectScreeningButton,
10
9
  )
@@ -14,8 +13,8 @@ from meta_screening.models import ScreeningPartOne, ScreeningPartThree, Screenin
14
13
 
15
14
  __all__ = [
16
15
  "SubjectScreeningPartOneButton",
17
- "SubjectScreeningPartTwoButton",
18
16
  "SubjectScreeningPartThreeButton",
17
+ "SubjectScreeningPartTwoButton",
19
18
  ]
20
19
 
21
20
 
@@ -38,17 +37,13 @@ class SubjectScreeningButton(BaseSubjectScreeningButton):
38
37
 
39
38
  @property
40
39
  def title(self) -> str:
41
- if self.perms.view_only or self.model_obj.consented:
42
- title = _("View")
43
- else:
44
- title = _("Edit")
45
- return title
40
+ return _("View") if self.perms.view_only or self.model_obj.consented else _("Edit")
46
41
 
47
42
 
48
43
  @dataclass
49
44
  class SubjectScreeningPartOneButton(SubjectScreeningButton):
50
- model_obj: ScreeningPartOne = None
51
- model_cls: Type[ScreeningPartOne] = field(default=ScreeningPartOne)
45
+ model_obj: ScreeningPartOne | None = None
46
+ model_cls: type[ScreeningPartOne] = field(default=ScreeningPartOne)
52
47
 
53
48
  @property
54
49
  def label(self) -> str:
@@ -57,8 +52,8 @@ class SubjectScreeningPartOneButton(SubjectScreeningButton):
57
52
 
58
53
  @dataclass
59
54
  class SubjectScreeningPartTwoButton(SubjectScreeningButton):
60
- model_obj: ScreeningPartTwo = None
61
- model_cls: Type[ScreeningPartTwo] = field(default=ScreeningPartTwo)
55
+ model_obj: ScreeningPartTwo | None = None
56
+ model_cls: type[ScreeningPartTwo] = field(default=ScreeningPartTwo)
62
57
 
63
58
  @property
64
59
  def label(self) -> str:
@@ -76,9 +71,8 @@ class SubjectScreeningPartTwoButton(SubjectScreeningButton):
76
71
  self._action = VIEW
77
72
  if self.model_obj.eligible_part_two == TBD:
78
73
  self._action = ADD
79
- elif self.model_obj:
80
- if self.perms.change:
81
- self._action = CHANGE
74
+ elif self.model_obj and self.perms.change:
75
+ self._action = CHANGE
82
76
  return self._action
83
77
 
84
78
  @property
@@ -90,8 +84,8 @@ class SubjectScreeningPartTwoButton(SubjectScreeningButton):
90
84
 
91
85
  @dataclass
92
86
  class SubjectScreeningPartThreeButton(SubjectScreeningButton):
93
- model_obj: ScreeningPartThree = None
94
- model_cls: Type[ScreeningPartThree] = field(default=ScreeningPartThree)
87
+ model_obj: ScreeningPartThree | None = None
88
+ model_cls: type[ScreeningPartThree] = field(default=ScreeningPartThree)
95
89
 
96
90
  @property
97
91
  def label(self) -> str:
@@ -109,9 +103,8 @@ class SubjectScreeningPartThreeButton(SubjectScreeningButton):
109
103
  self._action = VIEW
110
104
  if self.model_obj.eligible_part_three == TBD:
111
105
  self._action = ADD
112
- elif self.model_obj:
113
- if self.perms.change:
114
- self._action = CHANGE
106
+ elif self.model_obj and self.perms.change:
107
+ self._action = CHANGE
115
108
  return self._action
116
109
 
117
110
  @property
@@ -2,3 +2,11 @@ from .ae import AeListboardView, DeathReportListboardView
2
2
  from .screening import ListboardView as ScreeningListboardView
3
3
  from .subject import DashboardView as SubjectDashboardView
4
4
  from .subject import SubjectListboardView
5
+
6
+ __all__ = [
7
+ "AeListboardView",
8
+ "DeathReportListboardView",
9
+ "ScreeningListboardView",
10
+ "SubjectDashboardView",
11
+ "SubjectListboardView",
12
+ ]
@@ -1,2 +1,4 @@
1
1
  from .ae_listboard_view import AeListboardView
2
2
  from .death_report_listboard_view import DeathReportListboardView
3
+
4
+ __all__ = ["AeListboardView", "DeathReportListboardView"]
@@ -5,7 +5,7 @@ from meta_reports.ae_report import AePdfReport
5
5
 
6
6
 
7
7
  class CustomAeReport(AePdfReport):
8
- logo_data = {
8
+ logo_data = { # noqa: RUF012
9
9
  "app_label": "meta_edc",
10
10
  "filename": "meta_logo.png",
11
11
  "first_page": (4.0 * cm, 0.83 * cm),
@@ -5,7 +5,7 @@ from meta_reports.death_report import DeathPdfReport
5
5
 
6
6
 
7
7
  class CustomDeathReport(DeathPdfReport):
8
- logo_data = {
8
+ logo_data = { # noqa: RUF012
9
9
  "app_label": "meta_edc",
10
10
  "filename": "meta_logo.png",
11
11
  "first_page": (4.0 * cm, 0.83 * cm),
@@ -1 +1,3 @@
1
1
  from .listboard_view import ListboardView
2
+
3
+ __all__ = ["ListboardView"]
@@ -11,7 +11,6 @@ class ListboardView(ScreeningListboardView):
11
11
  kwargs.update(meta_version=get_meta_version())
12
12
  return super().get_context_data(**kwargs)
13
13
 
14
- def get_search_fields(self) -> list[str]:
14
+ def get_search_fields(self) -> tuple[str, ...]:
15
15
  fields = super().get_search_fields()
16
- fields.append("hospital_identifier__exact")
17
- return fields
16
+ return *fields, "hospital_identifier__exact"
@@ -1,2 +1,4 @@
1
1
  from .dashboard import DashboardView
2
2
  from .listboard import SubjectListboardView
3
+
4
+ __all__ = ["DashboardView", "SubjectListboardView"]
@@ -1 +1,3 @@
1
1
  from .dashboard_view import DashboardView
2
+
3
+ __all__ = ["DashboardView"]
@@ -1,9 +1,11 @@
1
1
  from typing import Any
2
2
 
3
+ from django.apps import apps as django_apps
3
4
  from django.core.checks import messages
4
5
  from django.core.exceptions import ObjectDoesNotExist
5
6
  from django.urls import reverse
6
7
  from django.utils.html import format_html
8
+ from django.utils.safestring import mark_safe
7
9
  from django.utils.translation import gettext_lazy as _
8
10
  from edc_subject_dashboard.views import SubjectDashboardView
9
11
 
@@ -18,19 +20,28 @@ class DashboardView(SubjectDashboardView):
18
20
 
19
21
  def get_context_data(self, **kwargs) -> dict[str, Any]:
20
22
  """Add message if subject reaches DM Endpoint."""
21
- context = super().get_context_data(**kwargs)
23
+ kwargs.update(subject_consent_v1_ext=self.subject_consent_v1_ext)
22
24
  try:
23
25
  Endpoints.objects.get(subject_identifier=self.subject_identifier)
24
26
  except ObjectDoesNotExist:
25
27
  pass
26
28
  else:
27
29
  url = reverse("meta_reports_admin:meta_reports_glucosesummary_changelist")
28
- url = f"{url}?q={self.subject_identifier}"
29
- message = _(
30
- format_html(
31
- f"Subject has reached the protocol endpoint. "
32
- f'See <A href="{url}">{GlucoseSummary._meta.verbose_name}</A>'
33
- )
30
+ url = mark_safe(f"{url}?q={self.subject_identifier}") # noqa: S308
31
+ message = format_html(
32
+ '{text} <A href="{url}">{verbose_name}</A>',
33
+ text=_("Subject has reached the protocol endpoint. See "),
34
+ url=url,
35
+ verbose_name=GlucoseSummary._meta.verbose_name,
34
36
  )
35
37
  self.message_user(message, level=messages.WARNING)
36
- return context
38
+ return super().get_context_data(**kwargs)
39
+
40
+ @property
41
+ def subject_consent_v1_ext(self):
42
+ model_cls = django_apps.get_model("meta_consent.subjectconsentv1ext")
43
+ try:
44
+ obj = model_cls.objects.get(subject_identifier=self.subject_identifier)
45
+ except ObjectDoesNotExist:
46
+ obj = None
47
+ return obj
@@ -1 +1,3 @@
1
1
  from .listboard_view import SubjectListboardView
2
+
3
+ __all__ = ["SubjectListboardView"]
@@ -11,7 +11,6 @@ class SubjectListboardView(BaseSubjectListboardView):
11
11
  kwargs.update(meta_version=get_meta_version())
12
12
  return super().get_context_data(**kwargs)
13
13
 
14
- def get_search_fields(self) -> list[str]:
14
+ def get_search_fields(self) -> tuple[str, ...]:
15
15
  fields = super().get_search_fields()
16
- fields.append("identity__exact")
17
- return fields
16
+ return *fields, "identity__exact"