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
@@ -28,11 +28,13 @@ def get_fieldsets():
28
28
  },
29
29
  )
30
30
 
31
- fieldsets = (fieldset,) + get_mnsi_fieldsets()
32
- fieldsets += (crf_status_fieldset_tuple,)
33
- fieldsets += (calculated_values_fieldset,)
34
- fieldsets += (audit_fieldset_tuple,)
35
- return fieldsets
31
+ return (
32
+ fieldset,
33
+ *get_mnsi_fieldsets(),
34
+ crf_status_fieldset_tuple,
35
+ calculated_values_fieldset,
36
+ audit_fieldset_tuple,
37
+ )
36
38
 
37
39
 
38
40
  edc_mnsi_admin.unregister(DefaultMnsi)
@@ -0,0 +1,19 @@
1
+ from __future__ import annotations
2
+
3
+ from django.contrib import admin
4
+ from edc_appointment.modeladmin_mixins import NextAppointmentCrfModelAdminMixin
5
+ from edc_model_admin.history import SimpleHistoryAdmin
6
+
7
+ from ..admin_site import meta_subject_admin
8
+ from ..forms import NextAppointmentForm
9
+ from ..models import NextAppointment
10
+ from .modeladmin import CrfModelAdminMixin
11
+
12
+ __all__ = ["NextAppointmentAdmin"]
13
+
14
+
15
+ @admin.register(NextAppointment, site=meta_subject_admin)
16
+ class NextAppointmentAdmin(
17
+ CrfModelAdminMixin, NextAppointmentCrfModelAdminMixin, SimpleHistoryAdmin
18
+ ):
19
+ form = NextAppointmentForm
@@ -15,7 +15,7 @@ class OtherArvRegimensInlineAdmin(TabularInlineMixin, admin.TabularInline):
15
15
  form = OtherArvRegimensDetailForm
16
16
  extra = 1
17
17
  view_on_site = False
18
- autocomplete_fields = ["arv_regimen"]
18
+ autocomplete_fields = ("arv_regimen",)
19
19
 
20
20
  fieldsets = (
21
21
  (
@@ -40,7 +40,7 @@ class OtherArvRegimensInlineAdmin(TabularInlineMixin, admin.TabularInline):
40
40
  class OtherArvRegimensAdmin(CrfModelAdminMixin, SimpleHistoryAdmin):
41
41
  form = OtherArvRegimensForm
42
42
 
43
- inlines = [OtherArvRegimensInlineAdmin]
43
+ inlines = (OtherArvRegimensInlineAdmin,)
44
44
 
45
45
  fieldsets = (
46
46
  (None, {"fields": ("subject_visit", "report_datetime", "has_other_regimens")}),
@@ -48,6 +48,6 @@ class OtherArvRegimensAdmin(CrfModelAdminMixin, SimpleHistoryAdmin):
48
48
  audit_fieldset_tuple,
49
49
  )
50
50
 
51
- radio_fields = {
51
+ radio_fields = { # noqa: RUF012
52
52
  "has_other_regimens": admin.VERTICAL,
53
53
  }
@@ -14,8 +14,8 @@ from .modeladmin import CrfModelAdminMixin
14
14
  class PatientHistoryAdmin(CrfModelAdminMixin, SimpleHistoryAdmin):
15
15
  form = PatientHistoryForm
16
16
 
17
- autocomplete_fields = ["current_arv_regimen", "previous_arv_regimen"]
18
- fieldsets = [
17
+ autocomplete_fields = ("current_arv_regimen", "previous_arv_regimen")
18
+ fieldsets = (
19
19
  (None, {"fields": ("subject_visit", "report_datetime")}),
20
20
  ("Part 1: Symptoms", {"fields": ("symptoms", "other_symptoms")}),
21
21
  get_hiv_fieldset(part="2"),
@@ -23,9 +23,9 @@ class PatientHistoryAdmin(CrfModelAdminMixin, SimpleHistoryAdmin):
23
23
  get_other_history_fieldset(part="4"),
24
24
  crf_status_fieldset,
25
25
  audit_fieldset_tuple,
26
- ]
26
+ )
27
27
 
28
- radio_fields = {
28
+ radio_fields = { # noqa: RUF012
29
29
  "current_arv_regimen": admin.VERTICAL,
30
30
  "current_smoker": admin.VERTICAL,
31
31
  "dm_in_family": admin.VERTICAL,
@@ -52,7 +52,7 @@ class PhysicalExamAdmin(CrfModelAdminMixin, SimpleHistoryAdmin):
52
52
  audit_fieldset_tuple,
53
53
  )
54
54
 
55
- radio_fields = {
55
+ radio_fields = { # noqa: RUF012
56
56
  "abdominal_tenderness": admin.VERTICAL,
57
57
  "enlarged_liver": admin.VERTICAL,
58
58
  "irregular_heartbeat": admin.VERTICAL,
@@ -28,6 +28,6 @@ class PregnancyUpdateAdmin(CrfModelAdminMixin, SimpleHistoryAdmin):
28
28
  audit_fieldset_tuple,
29
29
  )
30
30
 
31
- radio_fields = {
31
+ radio_fields = { # noqa: RUF012
32
32
  "contact": admin.VERTICAL,
33
33
  }
@@ -1,7 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from decimal import Decimal
4
- from typing import Type
5
4
 
6
5
  from django.contrib import admin, messages
7
6
  from django.contrib.admin import SimpleListFilter
@@ -30,15 +29,14 @@ from .modeladmin import CrfModelAdminMixin
30
29
 
31
30
  @admin.register(StudyMedication, site=meta_subject_admin)
32
31
  class StudyMedicationAdmin(CrfModelAdminMixin, SimpleHistoryAdmin):
33
-
34
- actions = ["create_or_update_rx_refills"]
32
+ actions = ("create_or_update_rx_refills",)
35
33
 
36
34
  form = StudyMedicationForm
37
35
 
38
- autocomplete_fields = [
36
+ autocomplete_fields = (
39
37
  "dosage_guideline",
40
38
  "formulation",
41
- ]
39
+ )
42
40
 
43
41
  fieldsets = (
44
42
  (
@@ -78,20 +76,19 @@ class StudyMedicationAdmin(CrfModelAdminMixin, SimpleHistoryAdmin):
78
76
  audit_fieldset_tuple,
79
77
  )
80
78
 
81
- radio_fields = {
79
+ radio_fields = { # noqa: RUF012
82
80
  "formulation": admin.VERTICAL,
83
81
  "refill": admin.VERTICAL,
84
82
  "refill_to_next_visit": admin.VERTICAL,
85
83
  }
86
84
 
87
- def get_list_filter(self, request) -> tuple[str | Type[SimpleListFilter], ...]:
85
+ def get_list_filter(self, request) -> tuple[str | type[SimpleListFilter], ...]:
88
86
  list_filter = super().get_list_filter(request)
89
87
  list_filter = list(list_filter)
90
88
  list_filter.insert(4, "dosage_guideline")
91
89
  list_filter.insert(4, RefillEndDateListFilter)
92
90
  list_filter.insert(4, RefillStartDateListFilter)
93
- list_filter = tuple(list_filter)
94
- return list_filter
91
+ return tuple(list_filter)
95
92
 
96
93
  def get_list_display(self, request) -> tuple[str, ...]:
97
94
  list_display = super().get_list_display(request)
@@ -100,8 +97,7 @@ class StudyMedicationAdmin(CrfModelAdminMixin, SimpleHistoryAdmin):
100
97
  list_display.insert(4, "refill_end_date")
101
98
  list_display.insert(4, "refill_start_date")
102
99
  list_display.insert(4, "dosage_guideline")
103
- list_display = tuple(list_display)
104
- return list_display
100
+ return tuple(list_display)
105
101
 
106
102
  @admin.display(description="days", ordering="number_of_days")
107
103
  def refill_days(self, obj):
@@ -156,10 +152,7 @@ class StudyMedicationAdmin(CrfModelAdminMixin, SimpleHistoryAdmin):
156
152
  messages.add_message(
157
153
  request,
158
154
  ERROR,
159
- (
160
- f"ObjectDoesNotExist: {obj.subject_identifier}, "
161
- f"{obj.related_visit}, {str(e)}"
162
- ),
155
+ (f"ObjectDoesNotExist: {obj.subject_identifier}, {obj.related_visit}, {e!s}"),
163
156
  )
164
157
  errors += 1
165
158
  except StudyMedicationError as e:
@@ -1,8 +1,8 @@
1
1
  from urllib.parse import parse_qs, urlsplit
2
2
 
3
+ from clinicedc_constants import YES
3
4
  from django.contrib import admin
4
5
  from django_audit_fields.admin import audit_fieldset_tuple
5
- from edc_constants.constants import YES
6
6
  from edc_lab.admin import (
7
7
  RequisitionAdminMixin,
8
8
  requisition_fieldset,
@@ -31,7 +31,7 @@ class SubjectRequisitionAdmin(RequisitionAdminMixin, CrfModelAdminMixin, SimpleH
31
31
  audit_fieldset_tuple,
32
32
  )
33
33
 
34
- radio_fields = {
34
+ radio_fields = { # noqa: RUF012
35
35
  "is_drawn": admin.VERTICAL,
36
36
  "reason_not_drawn": admin.VERTICAL,
37
37
  "item_type": admin.VERTICAL,
@@ -39,7 +39,7 @@ class SubjectVisitAdmin(
39
39
  audit_fieldset_tuple,
40
40
  )
41
41
 
42
- radio_fields = {
42
+ radio_fields = { # noqa: RUF012
43
43
  "reason": admin.VERTICAL,
44
44
  "reason_unscheduled": admin.VERTICAL,
45
45
  "info_source": admin.VERTICAL,
@@ -38,7 +38,7 @@ class SubjectVisitMissedAdmin(
38
38
 
39
39
  filter_horizontal = ("missed_reasons",)
40
40
 
41
- radio_fields = {
41
+ radio_fields = { # noqa: RUF012
42
42
  "survival_status": admin.VERTICAL,
43
43
  "contact_attempted": admin.VERTICAL,
44
44
  "contact_made": admin.VERTICAL,
@@ -32,7 +32,7 @@ class UrineDipstickTestAdmin(CrfModelAdminMixin, SimpleHistoryAdmin):
32
32
  audit_fieldset_tuple,
33
33
  )
34
34
 
35
- radio_fields = {
35
+ radio_fields = { # noqa: RUF012
36
36
  "performed": admin.VERTICAL,
37
37
  "ketones": admin.VERTICAL,
38
38
  "protein": admin.VERTICAL,
@@ -31,7 +31,7 @@ class UrinePregnancyAdmin(CrfModelAdminMixin, SimpleHistoryAdmin):
31
31
  audit_fieldset_tuple,
32
32
  )
33
33
 
34
- radio_fields = {
34
+ radio_fields = { # noqa: RUF012
35
35
  "performed": admin.VERTICAL,
36
36
  "bhcg_value": admin.VERTICAL,
37
37
  }
@@ -1,5 +1,5 @@
1
- from edc_constants.constants import NO, NOT_APPLICABLE, PATIENT, POS, YES
2
- from edc_utils import get_utcnow
1
+ from clinicedc_constants import NO, NOT_APPLICABLE, NULL_STRING, PATIENT, POS, YES
2
+ from django.utils import timezone
3
3
  from edc_visit_tracking.constants import SCHEDULED
4
4
  from faker import Faker
5
5
  from model_bakery.recipe import Recipe
@@ -26,22 +26,22 @@ subjectrequisition = Recipe(SubjectRequisition)
26
26
 
27
27
  medicationadherence = Recipe(
28
28
  MedicationAdherence,
29
- report_datetime=get_utcnow(),
29
+ report_datetime=timezone.now(),
30
30
  visual_score_slider=90,
31
31
  visual_score_confirmed=90,
32
32
  last_missed_pill=NO,
33
33
  pill_count_performed=YES,
34
34
  pill_count=3,
35
35
  missed_pill_reason=[],
36
- other_missed_pill_reason=None,
36
+ other_missed_pill_reason=NULL_STRING,
37
37
  )
38
38
 
39
39
  urinepregnancy = Recipe(
40
40
  UrinePregnancy,
41
- action_identifier=None,
42
- report_datetime=get_utcnow(),
41
+ action_identifier=NULL_STRING,
42
+ report_datetime=timezone.now(),
43
43
  performed=YES,
44
- not_performed_reason=None,
44
+ not_performed_reason=NULL_STRING,
45
45
  bhcg_value=POS,
46
46
  notified=False,
47
47
  notified_datetime=None,
@@ -79,16 +79,16 @@ followupexamination = Recipe(
79
79
  delivery = Recipe(
80
80
  Delivery,
81
81
  # site=None,
82
- action_identifier=None,
83
- report_datetime=get_utcnow(),
82
+ action_identifier=NULL_STRING,
83
+ report_datetime=timezone.now(),
84
84
  info_available=YES,
85
85
  info_source=PATIENT,
86
86
  informant_relation=NOT_APPLICABLE,
87
- informant_relation_other=None,
88
- delivery_datetime=get_utcnow(),
87
+ informant_relation_other=NULL_STRING,
88
+ delivery_datetime=timezone.now(),
89
89
  delivery_time_estimated=NO,
90
90
  delivery_location=HOSPITAL_CLINIC,
91
- delivery_location_other=None,
91
+ delivery_location_other=NULL_STRING,
92
92
  delivery_location_name="Big hospital",
93
93
  delivery_ga=40,
94
94
  gm_treated=NO,
@@ -98,8 +98,8 @@ delivery = Recipe(
98
98
  birthoutcomes = Recipe(
99
99
  BirthOutcomes,
100
100
  delivery=None,
101
- action_identifier=None,
102
- report_datetime=get_utcnow(),
101
+ action_identifier=NULL_STRING,
102
+ report_datetime=timezone.now(),
103
103
  birth_order=1,
104
104
  birth_outcome=LIVE_AT_TERM,
105
105
  birth_weight=320,
@@ -107,5 +107,5 @@ birthoutcomes = Recipe(
107
107
 
108
108
  healtheconomicsupdate = Recipe(
109
109
  HealthEconomicsUpdate,
110
- report_datetime=get_utcnow(),
110
+ report_datetime=timezone.now(),
111
111
  )
meta_subject/choices.py CHANGED
@@ -1,8 +1,9 @@
1
- from django.utils.translation import gettext_lazy as _
2
- from edc_constants.constants import (
1
+ from clinicedc_constants import (
3
2
  ABSENT,
4
3
  CLOSED,
5
4
  DEAD,
5
+ GRADE3,
6
+ GRADE4,
6
7
  NEW,
7
8
  NO,
8
9
  NO_EXAM,
@@ -15,7 +16,7 @@ from edc_constants.constants import (
15
16
  PRESENT_WITH_REINFORCEMENT,
16
17
  YES,
17
18
  )
18
- from edc_reportable.constants import GRADE3, GRADE4
19
+ from django.utils.translation import gettext_lazy as _
19
20
  from edc_visit_tracking.constants import MISSED_VISIT, SCHEDULED, UNSCHEDULED
20
21
 
21
22
  from meta_ae.choices import INFORMANT_RELATIONSHIP
@@ -4,5 +4,20 @@ from .dm_endpoint_form_validator import DmEndpointFormValidator
4
4
  from .dm_followup_form_validator import DmFollowupFormValidator
5
5
  from .egfr_drop_notification_form_validator import EgfrDropNotificationFormValidator
6
6
  from .followup_examination_form_validator import FollowupExaminationFormValidator
7
+ from .glucose_fbg_form_validator import GlucoseFbgFormValidator
7
8
  from .glucose_form_validator import GlucoseFormValidator
8
9
  from .health_economics_form_validator import HealthEconomicsFormValidator
10
+ from .hiv_exit_review_form_validator import HivExitReviewFormValidator
11
+
12
+ __all__ = [
13
+ "BirthOutcomesFormValidator",
14
+ "DeliveryFormValidator",
15
+ "DmEndpointFormValidator",
16
+ "DmFollowupFormValidator",
17
+ "EgfrDropNotificationFormValidator",
18
+ "FollowupExaminationFormValidator",
19
+ "GlucoseFbgFormValidator",
20
+ "GlucoseFormValidator",
21
+ "HealthEconomicsFormValidator",
22
+ "HivExitReviewFormValidator",
23
+ ]
@@ -1,6 +1,6 @@
1
+ from clinicedc_constants import NO, OTHER
1
2
  from django import forms
2
3
  from django.core.exceptions import ObjectDoesNotExist
3
- from edc_constants.constants import NO, OTHER
4
4
  from edc_crf.crf_form_validator import CrfFormValidator
5
5
  from edc_form_validators import INVALID_ERROR
6
6
  from edc_utils import formatted_date
@@ -15,10 +15,10 @@ class DeliveryFormValidator(CrfFormValidator):
15
15
  pregnancy_notification = PregnancyNotification.objects.get(
16
16
  subject_identifier=self.cleaned_data.get("subject_visit").subject_identifier
17
17
  )
18
- except ObjectDoesNotExist:
18
+ except ObjectDoesNotExist as e:
19
19
  raise forms.ValidationError(
20
20
  f"{PregnancyNotification._meta.verbose_name} not found."
21
- )
21
+ ) from e
22
22
 
23
23
  self.required_if(
24
24
  NO, field="info_available", field_required="info_not_available_reason"
@@ -2,6 +2,7 @@ from django.core.exceptions import ObjectDoesNotExist
2
2
  from django.template.loader import render_to_string
3
3
  from django.urls import reverse
4
4
  from django.utils.html import format_html
5
+ from django.utils.safestring import mark_safe
5
6
  from edc_crf.crf_form_validator import CrfFormValidator
6
7
  from edc_form_validators import INVALID_ERROR
7
8
 
@@ -28,7 +29,8 @@ class DmEndpointFormValidator(CrfFormValidator):
28
29
  self.raise_validation_error(
29
30
  {
30
31
  "__all__": format_html(
31
- f"Subject has not reached the protocol endpoint. See {link}"
32
+ "Subject has not reached the protocol endpoint. See {link}",
33
+ link=mark_safe(link), # noqa: S308
32
34
  )
33
35
  },
34
36
  INVALID_ERROR,
@@ -1,6 +1,6 @@
1
+ from clinicedc_constants import NO, OTHER, YES
1
2
  from django import forms
2
3
  from django.core.exceptions import ObjectDoesNotExist
3
- from edc_constants.constants import NO, OTHER, YES
4
4
  from edc_crf.crf_form_validator import CrfFormValidator
5
5
  from edc_form_validators import INVALID_ERROR
6
6
  from edc_utils import formatted_date
@@ -11,7 +11,6 @@ from meta_prn.models import DmReferral
11
11
 
12
12
  class DmFollowupFormValidator(CrfFormValidator):
13
13
  def clean(self):
14
-
15
14
  # referral_date must be before report datetime
16
15
  if (
17
16
  self.report_datetime
@@ -228,8 +227,10 @@ class DmFollowupFormValidator(CrfFormValidator):
228
227
  and self.cleaned_data.get("on_dm_medications") == YES
229
228
  ):
230
229
  confirmed = self.cleaned_data.get("visual_score_confirmed")
231
- if confirmed is not None:
232
- if int(self.cleaned_data.get("visual_score_slider", "0")) != confirmed:
233
- raise forms.ValidationError(
234
- {"visual_score_confirmed": "Does not match visual score above."}
235
- )
230
+ if (
231
+ confirmed is not None
232
+ and int(self.cleaned_data.get("visual_score_slider", "0")) != confirmed
233
+ ):
234
+ raise forms.ValidationError(
235
+ {"visual_score_confirmed": "Does not match visual score above."}
236
+ )
@@ -1,4 +1,4 @@
1
- from edc_constants.constants import CLOSED, NEW, OPEN
1
+ from clinicedc_constants import CLOSED, NEW, OPEN
2
2
  from edc_crf.crf_form_validator import CrfFormValidator
3
3
  from edc_form_validators import INVALID_ERROR
4
4
 
@@ -1,5 +1,5 @@
1
+ from clinicedc_constants import NONE, OTHER, YES
1
2
  from django import forms
2
- from edc_constants.constants import NONE, OTHER, YES
3
3
  from edc_crf.crf_form_validator import CrfFormValidator
4
4
 
5
5
 
@@ -0,0 +1,76 @@
1
+ from decimal import Decimal
2
+
3
+ from clinicedc_constants import MILLIMOLES_PER_LITER, NO, PENDING, YES
4
+ from clinicedc_utils import convert_units
5
+ from edc_crf.crf_form_validator import CrfFormValidator
6
+ from edc_form_validators import INVALID_ERROR
7
+ from edc_glucose.utils import validate_glucose_as_millimoles_per_liter
8
+
9
+ from meta_reports.models import GlucoseSummary
10
+
11
+ from .mixins import EndpointValidatorMixin, RepeatFbgDateValidatorMixin
12
+
13
+
14
+ class GlucoseFbgFormValidator(
15
+ EndpointValidatorMixin, RepeatFbgDateValidatorMixin, CrfFormValidator
16
+ ):
17
+ def clean(self):
18
+ self.required_if(YES, field="fasting", field_required="fasting_duration_str")
19
+ self.required_if(NO, field="fbg_performed", field_required="fbg_not_performed_reason")
20
+ self.required_if(YES, field="fbg_performed", field_required="fbg_datetime")
21
+ if self.cleaned_data.get("fbg_datetime") and self.cleaned_data.get(
22
+ "fbg_datetime"
23
+ ) < self.cleaned_data.get("report_datetime"):
24
+ self.raise_validation_error(
25
+ {"fbg_datetime": "Invalid. Must be on or after report date above"},
26
+ INVALID_ERROR,
27
+ )
28
+ self.required_if(YES, field="fbg_performed", field_required="fbg_value")
29
+
30
+ self.applicable_if(YES, field="fbg_performed", field_applicable="fbg_units")
31
+
32
+ # endpoint
33
+ self.applicable_if(YES, field="fbg_performed", field_applicable="endpoint_today")
34
+ self.validate_endpoint_fields()
35
+
36
+ # repeat_fbg_date
37
+ self.required_if(PENDING, field="endpoint_today", field_required="repeat_fbg_date")
38
+ self.validate_repeat_fbg_date()
39
+
40
+ @property
41
+ def converted_fbg_value(self):
42
+ if self.cleaned_data.get("fbg_value") is not None:
43
+ return validate_glucose_as_millimoles_per_liter("fbg", self.cleaned_data)
44
+ return None
45
+
46
+ def is_endpoint(self):
47
+ value = NO
48
+ if self.converted_fbg_value and self.converted_fbg_value >= Decimal("7.0"):
49
+ # is there a previous FBG>=7.0 in sequence or do you need to repeat?
50
+ previous_obj = (
51
+ GlucoseSummary.objects.filter(
52
+ subject_identifier=self.subject_identifier,
53
+ fbg_datetime__lt=self.cleaned_data.get("fbg_datetime"),
54
+ )
55
+ .order_by("fbg_datetime")
56
+ .last()
57
+ )
58
+ previous_fbg_value = convert_units(
59
+ label="fbg",
60
+ value=float(previous_obj.fbg_value),
61
+ units_from=previous_obj.fbg_units,
62
+ units_to=MILLIMOLES_PER_LITER,
63
+ )
64
+ previous_ogtt_value = convert_units(
65
+ label="ogtt",
66
+ value=float(previous_obj.ogtt_value),
67
+ units_from=previous_obj.ogtt_units,
68
+ units_to=MILLIMOLES_PER_LITER,
69
+ )
70
+
71
+ if previous_obj and previous_fbg_value >= 7.0 and previous_ogtt_value <= 11.1:
72
+ value = YES
73
+ else:
74
+ # you need to schedule a repeat
75
+ value = PENDING
76
+ return value
@@ -1,14 +1,17 @@
1
- from decimal import Decimal
2
-
3
- from edc_constants.constants import NO, PENDING, YES
1
+ from clinicedc_constants import PENDING
4
2
  from edc_crf.crf_form_validator import CrfFormValidator
5
- from edc_form_validators import INVALID_ERROR
6
3
  from edc_glucose.form_validators import FbgOgttFormValidatorMixin
7
4
 
8
5
  from ..constants import AMENDMENT_DATE
6
+ from .mixins import EndpointValidatorMixin, RepeatFbgDateValidatorMixin
9
7
 
10
8
 
11
- class GlucoseFormValidator(FbgOgttFormValidatorMixin, CrfFormValidator):
9
+ class GlucoseFormValidator(
10
+ EndpointValidatorMixin,
11
+ RepeatFbgDateValidatorMixin,
12
+ FbgOgttFormValidatorMixin,
13
+ CrfFormValidator,
14
+ ):
12
15
  def clean(self):
13
16
  self.validate_glucose_testing_matrix()
14
17
  has_results = (
@@ -18,66 +21,6 @@ class GlucoseFormValidator(FbgOgttFormValidatorMixin, CrfFormValidator):
18
21
  )
19
22
  self.applicable_if_true(has_results, field_applicable="endpoint_today")
20
23
  if has_results:
21
- is_endpoint = self.is_endpoint()
22
- if is_endpoint == YES and self.cleaned_data.get("endpoint_today") != YES:
23
- self.raise_validation_error(
24
- {
25
- "endpoint_today": (
26
- "Participant has reached a study endpoint today. Expected YES"
27
- )
28
- },
29
- INVALID_ERROR,
30
- )
31
- elif is_endpoint == PENDING and self.cleaned_data.get("endpoint_today") != PENDING:
32
- self.raise_validation_error(
33
- {
34
- "endpoint_today": (
35
- "Participant has not reached a study endpoint today. "
36
- "Expected to repeat FBG"
37
- )
38
- },
39
- INVALID_ERROR,
40
- )
41
-
42
- elif is_endpoint == NO and self.cleaned_data.get("endpoint_today") != NO:
43
- self.raise_validation_error(
44
- {"endpoint_today": "Participant has not reached a study endpoint today"},
45
- INVALID_ERROR,
46
- )
47
-
24
+ self.validate_endpoint_fields()
48
25
  self.required_if(PENDING, field="endpoint_today", field_required="repeat_fbg_date")
49
- if self.cleaned_data.get("repeat_fbg_date"):
50
- delta = (
51
- self.cleaned_data.get("repeat_fbg_date")
52
- - self.cleaned_data.get("fbg_datetime").date()
53
- )
54
- if delta.days < 7:
55
- self.raise_validation_error(
56
- {"repeat_fbg_date": "Must be at least 7 days from the FBG date above"},
57
- INVALID_ERROR,
58
- )
59
- if delta.days > 10:
60
- self.raise_validation_error(
61
- {
62
- "repeat_fbg_date": (
63
- "Must be no more than 10 days from the FBG date above"
64
- )
65
- },
66
- INVALID_ERROR,
67
- )
68
-
69
- def is_endpoint(self):
70
- value = NO
71
- if self.cleaned_data.get("fbg_value") >= Decimal("7.0") and self.cleaned_data.get(
72
- "ogtt_value"
73
- ) >= Decimal("11.1"):
74
- value = YES
75
- elif self.cleaned_data.get("fbg_value") < Decimal("7.0") and self.cleaned_data.get(
76
- "ogtt_value"
77
- ) >= Decimal("11.1"):
78
- value = YES
79
- elif self.cleaned_data.get("fbg_value") >= Decimal("7.0") and self.cleaned_data.get(
80
- "ogtt_value"
81
- ) < Decimal("11.1"):
82
- value = PENDING
83
- return value
26
+ self.validate_repeat_fbg_date()
@@ -0,0 +1,18 @@
1
+ from clinicedc_constants import NO, OTHER
2
+ from edc_crf.crf_form_validator import CrfFormValidator
3
+
4
+
5
+ class HivExitReviewFormValidator(CrfFormValidator):
6
+ def clean(self):
7
+ self.required_if(NO, field="available", field_required="not_available_reason")
8
+ self.required_if_not_none(
9
+ "viral_load", "viral_load_date", field_required_evaluate_as_int=True
10
+ )
11
+
12
+ self.required_if_not_none("cd4", "cd4_date", field_required_evaluate_as_int=True)
13
+
14
+ self.required_if(
15
+ OTHER,
16
+ field="current_arv_regimen",
17
+ field_required="other_current_arv_regimen",
18
+ )