meta-edc 1.1.8__py3-none-any.whl → 1.1.12__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of meta-edc might be problematic. Click here for more details.

Files changed (475) hide show
  1. meta_ae/action_items.py +2 -1
  2. meta_ae/admin/__init__.py +11 -0
  3. meta_ae/admin/ae_susar_admin.py +1 -1
  4. meta_ae/admin/death_report_admin.py +1 -1
  5. meta_ae/admin/modeladmin_mixins.py +10 -12
  6. meta_ae/baker_recipes.py +3 -3
  7. meta_ae/forms/__init__.py +13 -0
  8. meta_ae/forms/modelform_mixins.py +2 -2
  9. meta_ae/migrations/0001_initial.py +27 -27
  10. meta_ae/migrations/0006_aelocalreview_aesponsorreview.py +5 -5
  11. meta_ae/migrations/0022_historicalhospitalization_hospitalization.py +5 -13
  12. meta_ae/migrations/0023_alter_aefollowup_action_identifier_and_more.py +2017 -0
  13. meta_ae/model_mixins/__init__.py +2 -0
  14. meta_ae/model_mixins/ae_review_model_mixin.py +6 -6
  15. meta_ae/model_mixins/death_report_model_mixin.py +3 -3
  16. meta_ae/models/__init__.py +13 -0
  17. meta_ae/models/hospitalization.py +3 -3
  18. meta_ae/pdf_reports/__init__.py +2 -0
  19. meta_analytics/.DS_Store +0 -0
  20. meta_analytics/dataframes/__init__.py +24 -0
  21. meta_analytics/dataframes/get_eos_df.py +1 -2
  22. meta_analytics/dataframes/get_glucose_df.py +6 -7
  23. meta_analytics/dataframes/get_glucose_fbg_df.py +2 -3
  24. meta_analytics/dataframes/get_glucose_fbg_ogtt_df.py +1 -2
  25. meta_analytics/dataframes/get_last_imp_visits_df.py +5 -6
  26. meta_analytics/dataframes/glucose_endpoints/__init__.py +2 -0
  27. meta_analytics/dataframes/glucose_endpoints/endpoint_by_date.py +13 -20
  28. meta_analytics/dataframes/glucose_endpoints/glucose_endpoints_by_date.py +9 -10
  29. meta_analytics/dataframes/screening/__init__.py +2 -0
  30. meta_analytics/dataframes/screening/get_glucose_tested_only_df.py +1 -2
  31. meta_analytics/dataframes/screening/get_screening_df.py +6 -10
  32. meta_analytics/dataframes/utils.py +3 -8
  33. meta_analytics/get_tables.py +1 -2
  34. meta_analytics/tables/__init__.py +2 -0
  35. meta_consent/action_items.py +2 -1
  36. meta_consent/admin/__init__.py +6 -0
  37. meta_consent/admin/actions/__init__.py +2 -0
  38. meta_consent/admin/actions/create_missing_prescriptions.py +1 -1
  39. meta_consent/admin/list_filters.py +2 -2
  40. meta_consent/admin/modeladmin_mixins.py +3 -4
  41. meta_consent/admin/subject_consent_v1_ext_admin.py +2 -2
  42. meta_consent/baker_recipes.py +7 -8
  43. meta_consent/form_validators/__init__.py +2 -0
  44. meta_consent/forms/__init__.py +7 -0
  45. meta_consent/forms/subject_consent_v1_ext_form.py +2 -3
  46. meta_consent/forms/subject_reconsent_form.py +4 -4
  47. meta_consent/management/commands/create_missing_prescriptions.py +4 -2
  48. meta_consent/migrations/0001_initial.py +9 -9
  49. meta_consent/migrations/0024_historicalsubjectconsentv1.py +3 -8
  50. meta_consent/migrations/0026_historicalsubjectconsentv1ext_subjectconsentv1ext.py +5 -14
  51. meta_consent/migrations/0032_alter_historicalsubjectconsent_device_created_and_more.py +678 -0
  52. meta_consent/models/__init__.py +9 -0
  53. meta_consent/models/model_mixins.py +1 -2
  54. meta_consent/models/signals.py +9 -10
  55. meta_consent/models/subject_consent.py +1 -1
  56. meta_consent/models/subject_reconsent.py +3 -3
  57. meta_dashboard/patterns.py +1 -1
  58. meta_dashboard/templatetags/meta_dashboard_extras.py +1 -1
  59. meta_dashboard/view_utils/__init__.py +7 -0
  60. meta_dashboard/view_utils/subject_screening_button.py +9 -16
  61. meta_dashboard/views/__init__.py +8 -0
  62. meta_dashboard/views/ae/__init__.py +2 -0
  63. meta_dashboard/views/ae/ae_listboard_view.py +1 -1
  64. meta_dashboard/views/ae/death_report_listboard_view.py +1 -1
  65. meta_dashboard/views/screening/__init__.py +2 -0
  66. meta_dashboard/views/subject/__init__.py +2 -0
  67. meta_dashboard/views/subject/dashboard/__init__.py +2 -0
  68. meta_dashboard/views/subject/dashboard/dashboard_view.py +1 -1
  69. meta_dashboard/views/subject/listboard/__init__.py +2 -0
  70. meta_edc/__init__.py +5 -9
  71. meta_edc/celery.py +1 -1
  72. meta_edc/celery_live.py +1 -1
  73. meta_edc/celery_uat.py +1 -1
  74. meta_edc/management/commands/update_forms_reference.py +10 -12
  75. meta_edc/settings/debug.py +5 -4
  76. meta_edc/settings/defaults.py +18 -3
  77. meta_edc/settings/live.py +3 -1
  78. meta_edc/settings/logging.py +9 -4
  79. meta_edc/settings/minimal.py +4 -5
  80. meta_edc/settings/uat.py +3 -1
  81. meta_edc/views/__init__.py +2 -0
  82. meta_edc-1.1.12.dist-info/METADATA +174 -0
  83. {meta_edc-1.1.8.dist-info → meta_edc-1.1.12.dist-info}/RECORD +413 -526
  84. meta_edc-1.1.12.dist-info/WHEEL +4 -0
  85. meta_lists/migrations/0020_alter_abnormalfootappearanceobservations_extra_value_and_more.py +404 -0
  86. meta_pharmacy/admin/__init__.py +5 -0
  87. meta_pharmacy/admin/substitutions_admin.py +2 -2
  88. meta_pharmacy/forms/__init__.py +2 -0
  89. meta_pharmacy/forms/substitutions_form.py +6 -4
  90. meta_pharmacy/labels/__init__.py +4 -2
  91. meta_pharmacy/labels/draw_label_for_subject_with_barcode.py +1 -2
  92. meta_pharmacy/labels/draw_label_with_test_data.py +2 -2
  93. meta_pharmacy/labels/label_data.py +1 -2
  94. meta_pharmacy/labels/print_sheets.py +4 -6
  95. meta_pharmacy/migrations/0002_initial.py +7 -20
  96. meta_pharmacy/migrations/0003_auto_20240909_2335.py +3 -2
  97. meta_pharmacy/migrations/0006_lotnumber_label.py +5 -14
  98. meta_pharmacy/migrations/0008_remove_lotnumber_medication_and_more.py +5 -6
  99. meta_pharmacy/migrations/0010_alter_historicallabeldata_device_created_and_more.py +382 -0
  100. meta_pharmacy/models/__init__.py +7 -0
  101. meta_pharmacy/models/label_data.py +4 -5
  102. meta_pharmacy/models/substitutions.py +3 -3
  103. meta_pharmacy/prepare_meta_pharmacy.py +1 -1
  104. meta_pharmacy/utils/__init__.py +2 -0
  105. meta_pharmacy/utils/update_initial_pharmacy_data.py +1 -1
  106. meta_prn/admin/__init__.py +16 -0
  107. meta_prn/admin/dm_referral_admin.py +2 -1
  108. meta_prn/admin/end_of_study_admin.py +6 -7
  109. meta_prn/admin/loss_to_followup_admin.py +3 -2
  110. meta_prn/admin/off_study_medication_admin.py +5 -6
  111. meta_prn/admin/offschedule_admin.py +5 -6
  112. meta_prn/admin/offschedule_dm_referral_admin.py +6 -6
  113. meta_prn/admin/offschedule_postnatal_admin.py +7 -7
  114. meta_prn/admin/offschedule_pregnancy_admin.py +8 -7
  115. meta_prn/admin/onschedule_admin.py +7 -8
  116. meta_prn/admin/onschedule_dm_referral_admin.py +6 -7
  117. meta_prn/admin/pregnancy_notification_admin.py +5 -6
  118. meta_prn/admin/protocol_incident_admin.py +1 -1
  119. meta_prn/admin/subject_transfer_admin.py +1 -1
  120. meta_prn/baker_recipes.py +4 -4
  121. meta_prn/form_validators/__init__.py +5 -0
  122. meta_prn/form_validators/end_of_study.py +2 -2
  123. meta_prn/forms/__init__.py +13 -0
  124. meta_prn/migrations/0001_initial.py +25 -25
  125. meta_prn/migrations/0017_auto_20220307_1929.py +5 -5
  126. meta_prn/migrations/0018_auto_20220309_2106.py +9 -9
  127. meta_prn/migrations/0021_auto_20220316_2147.py +13 -13
  128. meta_prn/migrations/0022_auto_20220318_0133.py +9 -9
  129. meta_prn/migrations/0032_historicalegfrnotification_egfrnotification.py +5 -13
  130. meta_prn/migrations/0038_alter_endofstudy_delivery_date_and_more.py +5 -13
  131. meta_prn/migrations/0041_endofstudy_transfer_date_and_more.py +5 -13
  132. meta_prn/migrations/0057_historicalonscheduledmreferral_and_more.py +13 -38
  133. meta_prn/migrations/0067_alter_offschedule_managers_and_more.py +2557 -0
  134. meta_prn/models/__init__.py +20 -0
  135. meta_prn/models/offschedule.py +4 -4
  136. meta_prn/models/protocol_incident.py +1 -1
  137. meta_prn/models/subject_transfer.py +8 -0
  138. meta_rando/migrations/0001_initial.py +5 -5
  139. meta_rando/migrations/0006_alter_historicalrandomizationlist_allocated_user_and_more.py +130 -0
  140. meta_reports/__init__.py +2 -0
  141. meta_reports/admin/__init__.py +16 -0
  142. meta_reports/admin/dbviews/__init__.py +13 -0
  143. meta_reports/admin/dbviews/glucose_summary_admin.py +6 -6
  144. meta_reports/admin/dbviews/imp_substitutions_admin.py +12 -11
  145. meta_reports/admin/dbviews/missing_screening_ogtt_admin/__init__.py +5 -0
  146. meta_reports/admin/dbviews/missing_screening_ogtt_admin/note_model_admin.py +27 -3
  147. meta_reports/admin/dbviews/missing_screening_ogtt_admin/unmanaged_model_admin.py +6 -6
  148. meta_reports/admin/dbviews/on_study_missing_lab_values_admin/__init__.py +2 -0
  149. meta_reports/admin/dbviews/on_study_missing_lab_values_admin/unmanaged_model_admin.py +0 -3
  150. meta_reports/admin/dbviews/on_study_missing_values_admin/__init__.py +2 -0
  151. meta_reports/admin/dbviews/patient_history_missing_baseline_cd4_admin.py +8 -8
  152. meta_reports/admin/dbviews/unattended_three_in_row2_admin.py +6 -6
  153. meta_reports/admin/dbviews/unattended_three_in_row_admin.py +5 -5
  154. meta_reports/admin/dbviews/unattended_two_in_row_admin.py +5 -5
  155. meta_reports/admin/endpoints_admin.py +1 -1
  156. meta_reports/admin/last_imp_refill_admin.py +9 -9
  157. meta_reports/admin/list_filters.py +2 -2
  158. meta_reports/admin/modeladmin_mixins.py +9 -16
  159. meta_reports/death_report.py +1 -1
  160. meta_reports/forms/__init__.py +2 -0
  161. meta_reports/forms/missing_ogtt_note_form.py +2 -3
  162. meta_reports/management/commands/generate_endpoints.py +5 -4
  163. meta_reports/migrations/0035_historicalmissingogttnote_missingogttnote.py +5 -14
  164. meta_reports/migrations/0059_alter_endpoints_created_and_more.py +161 -0
  165. meta_reports/models/__init__.py +17 -0
  166. meta_reports/models/dbviews/__init__.py +14 -0
  167. meta_reports/models/dbviews/glucose_summary/__init__.py +2 -0
  168. meta_reports/models/dbviews/glucose_summary/unmanaged_model.py +4 -5
  169. meta_reports/models/dbviews/imp_substitutions/__init__.py +2 -0
  170. meta_reports/models/dbviews/imp_substitutions/view_definition.py +1 -1
  171. meta_reports/models/dbviews/missing_screening_ogtt/__init__.py +2 -0
  172. meta_reports/models/dbviews/missing_screening_ogtt/note_model.py +1 -1
  173. meta_reports/models/dbviews/missing_screening_ogtt/unmanaged_model.py +4 -3
  174. meta_reports/models/dbviews/on_study_missing_lab_values/__init__.py +2 -0
  175. meta_reports/models/dbviews/on_study_missing_lab_values/qa_cases.py +13 -11
  176. meta_reports/models/dbviews/on_study_missing_values/__init__.py +2 -0
  177. meta_reports/models/dbviews/on_study_missing_values/qa_cases.py +18 -0
  178. meta_reports/models/dbviews/patient_history_missing_baseline_cd4/__init__.py +2 -0
  179. meta_reports/models/dbviews/unattended_three_in_row/__init__.py +2 -0
  180. meta_reports/models/dbviews/unattended_three_in_row2/__init__.py +2 -0
  181. meta_reports/models/dbviews/unattended_two_in_row/__init__.py +2 -0
  182. meta_reports/models/endpoints.py +4 -4
  183. meta_reports/models/last_imp_refill.py +2 -3
  184. meta_reports/pdf_report.py +2 -2
  185. meta_reports/tasks.py +1 -1
  186. meta_screening/admin/__init__.py +8 -0
  187. meta_screening/admin/fieldsets.py +13 -14
  188. meta_screening/admin/list_filters.py +6 -4
  189. meta_screening/admin/screening_part_one_admin.py +1 -2
  190. meta_screening/admin/screening_part_three_admin.py +2 -3
  191. meta_screening/admin/screening_part_two_admin.py +7 -10
  192. meta_screening/admin/subject_refusal_admin.py +5 -3
  193. meta_screening/admin/subject_screening_admin.py +4 -4
  194. meta_screening/baker_recipes.py +9 -9
  195. meta_screening/eligibility/__init__.py +9 -0
  196. meta_screening/eligibility/eligibility.py +7 -7
  197. meta_screening/eligibility/eligibility_part_three/__init__.py +2 -0
  198. meta_screening/eligibility/eligibility_part_three/base_eligibility_part_three.py +8 -8
  199. meta_screening/eligibility/eligibility_part_three/eligibility_part_three_phase_three.py +13 -14
  200. meta_screening/form_validators/__init__.py +8 -0
  201. meta_screening/forms/__init__.py +20 -0
  202. meta_screening/forms/field_lists.py +16 -17
  203. meta_screening/forms/screening_part_one_form.py +2 -2
  204. meta_screening/forms/screening_part_three_form.py +5 -3
  205. meta_screening/forms/screening_part_two_form.py +1 -5
  206. meta_screening/forms/subject_refusal_form.py +0 -4
  207. meta_screening/forms/subject_screening_form.py +0 -4
  208. meta_screening/migrations/0001_initial.py +15 -15
  209. meta_screening/migrations/0010_auto_20191106_0828.py +5 -5
  210. meta_screening/migrations/0068_alter_historicalscreeningpartone_acute_condition_and_more.py +1579 -0
  211. meta_screening/model_mixins/__init__.py +8 -0
  212. meta_screening/model_mixins/eligibility_model_mixin.py +5 -3
  213. meta_screening/model_mixins/part_one_fields_model_mixin.py +5 -9
  214. meta_screening/model_mixins/part_three_fields_model_mixin.py +5 -6
  215. meta_screening/model_mixins/part_two_fields_model_mixin.py +18 -16
  216. meta_screening/models/__init__.py +9 -0
  217. meta_screening/models/icp_referral.py +5 -5
  218. meta_screening/models/signals.py +10 -11
  219. meta_screening/models/subject_refusal.py +1 -1
  220. meta_screening/models/subject_screening.py +1 -3
  221. meta_subject/action_items.py +13 -15
  222. meta_subject/admin/__init__.py +39 -0
  223. meta_subject/admin/birth_outcome_admin.py +4 -8
  224. meta_subject/admin/blood_results/__init__.py +9 -0
  225. meta_subject/admin/blood_results/blood_results_fbc_admin.py +1 -1
  226. meta_subject/admin/blood_results/blood_results_hba1c_admin.py +1 -1
  227. meta_subject/admin/blood_results/blood_results_ins_admin.py +1 -1
  228. meta_subject/admin/blood_results/blood_results_lft_admin.py +1 -1
  229. meta_subject/admin/blood_results/blood_results_lipids_admin.py +1 -1
  230. meta_subject/admin/blood_results/blood_results_rft_admin.py +3 -5
  231. meta_subject/admin/complications_glycemia_admin.py +1 -1
  232. meta_subject/admin/delivery_admin.py +7 -10
  233. meta_subject/admin/diabetes/__init__.py +2 -0
  234. meta_subject/admin/diabetes/dm_endpoint_admin.py +2 -2
  235. meta_subject/admin/diabetes/dm_followup_admin.py +3 -2
  236. meta_subject/admin/egfr_drop_notification_admin.py +1 -1
  237. meta_subject/admin/followup_examination_admin.py +10 -9
  238. meta_subject/admin/followup_vitals_admin.py +4 -5
  239. meta_subject/admin/glucose_admin.py +2 -4
  240. meta_subject/admin/glucose_fbg_admin.py +1 -3
  241. meta_subject/admin/health_economics/__init__.py +2 -0
  242. meta_subject/admin/health_economics/health_economics_simple_admin.py +1 -1
  243. meta_subject/admin/health_economics/health_economics_update_admin.py +1 -1
  244. meta_subject/admin/hepatitis_test_admin.py +1 -1
  245. meta_subject/admin/list_filters.py +1 -1
  246. meta_subject/admin/mnsi_admin.py +7 -5
  247. meta_subject/admin/other_arv_regimens_admin.py +3 -3
  248. meta_subject/admin/patient_history_admin.py +4 -4
  249. meta_subject/admin/physical_exam_admin.py +1 -1
  250. meta_subject/admin/pregnancy_update_admin.py +1 -1
  251. meta_subject/admin/study_medication_admin.py +8 -15
  252. meta_subject/admin/subject_requisition_admin.py +1 -1
  253. meta_subject/admin/subject_visit_admin.py +1 -1
  254. meta_subject/admin/subject_visit_missed_admin.py +1 -1
  255. meta_subject/admin/urine_dipstick_test_admin.py +1 -1
  256. meta_subject/admin/urine_pregnancy_admin.py +1 -1
  257. meta_subject/baker_recipes.py +15 -15
  258. meta_subject/form_validators/__init__.py +11 -0
  259. meta_subject/form_validators/delivery_form_validator.py +2 -3
  260. meta_subject/form_validators/dm_endpoint_form_validator.py +1 -1
  261. meta_subject/form_validators/dm_followup_form_validator.py +7 -6
  262. meta_subject/form_validators/glucose_form_validator.py +3 -5
  263. meta_subject/forms/__init__.py +41 -0
  264. meta_subject/forms/blood_results/__init__.py +9 -0
  265. meta_subject/forms/blood_results/blood_results_rft_form.py +1 -2
  266. meta_subject/forms/diabetes/__init__.py +2 -0
  267. meta_subject/forms/diabetes/dm_followup_form.py +2 -2
  268. meta_subject/forms/followup_vitals_form.py +3 -8
  269. meta_subject/forms/health_economics/__init__.py +2 -0
  270. meta_subject/forms/next_appointment_form.py +2 -3
  271. meta_subject/forms/slider_widget.py +1 -1
  272. meta_subject/forms/study_medication_form.py +11 -8
  273. meta_subject/management/commands/create_missing_refills.py +3 -3
  274. meta_subject/management/commands/create_missing_rx.py +1 -1
  275. meta_subject/management/commands/missed.py +20 -23
  276. meta_subject/metadata_rules/__init__.py +2 -0
  277. meta_subject/metadata_rules/predicates.py +25 -32
  278. meta_subject/migrations/0001_initial.py +61 -61
  279. meta_subject/migrations/0002_auto_20191021_0353.py +5 -5
  280. meta_subject/migrations/0012_auto_20200118_2334.py +5 -5
  281. meta_subject/migrations/0014_auto_20200120_1622.py +5 -5
  282. meta_subject/migrations/0018_coronakap_historicalcoronakap.py +5 -5
  283. meta_subject/migrations/0033_auto_20200516_2356.py +5 -5
  284. meta_subject/migrations/0038_auto_20200520_0020.py +5 -5
  285. meta_subject/migrations/0040_auto_20200527_2155.py +1 -1
  286. meta_subject/migrations/0045_auto_20200530_1801.py +1 -1
  287. meta_subject/migrations/0051_auto_20200617_2117.py +5 -5
  288. meta_subject/migrations/0063_auto_20210715_0337.py +5 -5
  289. meta_subject/migrations/0066_auto_20210721_0335.py +9 -9
  290. meta_subject/migrations/0067_auto_20210726_0340.py +5 -5
  291. meta_subject/migrations/0068_auto_20210728_1809.py +5 -5
  292. meta_subject/migrations/0072_auto_20210805_1545.py +7 -7
  293. meta_subject/migrations/0073_auto_20210809_0055.py +5 -5
  294. meta_subject/migrations/0077_auto_20210809_2323.py +3 -3
  295. meta_subject/migrations/0082_auto_20210823_1612.py +3 -3
  296. meta_subject/migrations/0083_auto_20210823_1620.py +3 -3
  297. meta_subject/migrations/0088_auto_20210924_0027.py +5 -5
  298. meta_subject/migrations/0090_auto_20210924_0424.py +5 -5
  299. meta_subject/migrations/0093_auto_20211117_0352.py +5 -5
  300. meta_subject/migrations/0095_auto_20220128_1719.py +5 -5
  301. meta_subject/migrations/0098_auto_20220309_2106.py +5 -5
  302. meta_subject/migrations/0101_auto_20220316_2147.py +13 -13
  303. meta_subject/migrations/0115_historicalegfrnotification_egfrnotification.py +5 -13
  304. meta_subject/migrations/0164_dmreferralfollowup_historicaldmreferralfollowup.py +5 -5
  305. meta_subject/migrations/0172_remove_historicalbloodresultsglu_action_item_and_more.py +1 -2
  306. meta_subject/migrations/0177_alter_bloodresultslft_alp_value_and_more.py +1 -2
  307. meta_subject/migrations/0178_historicalhealtheconomicsupdate_and_more.py +5 -14
  308. meta_subject/migrations/0186_healtheconomicsupdate_singleton_field_and_more.py +1 -2
  309. meta_subject/migrations/0187_dmdiagnosis_historicaldmdiagnosis_dmdxresult_and_more.py +5 -14
  310. meta_subject/migrations/0188_historicaldmdxresult_dmdxresult.py +5 -14
  311. meta_subject/migrations/0209_remove_historicaldmdxresult_dm_diagnosis_and_more.py +1 -2
  312. meta_subject/migrations/0216_historicalnextappointment_nextappointment.py +5 -6
  313. meta_subject/migrations/0220_historicalbloodresultsgludummy_bloodresultsgludummy.py +5 -14
  314. meta_subject/migrations/0227_alter_followupvitals_waist_circumference_comment_and_more.py +97 -0
  315. meta_subject/migrations/0228_bloodresultshba1c_hba1c_datetime_and_more.py +9297 -0
  316. meta_subject/model_mixins/__init__.py +8 -0
  317. meta_subject/model_mixins/search_slug_model_mixin.py +1 -2
  318. meta_subject/model_mixins/vitals_fields_model_mixin.py +1 -1
  319. meta_subject/models/__init__.py +48 -0
  320. meta_subject/models/birth_outcomes.py +3 -3
  321. meta_subject/models/blood_results/__init__.py +11 -0
  322. meta_subject/models/delivery.py +3 -3
  323. meta_subject/models/diabetes/__init__.py +2 -0
  324. meta_subject/models/diabetes/dm_endpoint.py +4 -4
  325. meta_subject/models/diabetes/dm_followup.py +3 -4
  326. meta_subject/models/diet_and_lifestyle.py +2 -2
  327. meta_subject/models/followup_examination.py +11 -11
  328. meta_subject/models/glucose.py +4 -4
  329. meta_subject/models/glucose_fbg.py +2 -3
  330. meta_subject/models/health_economics/__init__.py +2 -0
  331. meta_subject/models/health_economics/health_economics.py +7 -7
  332. meta_subject/models/health_economics/health_economics_update.py +2 -1
  333. meta_subject/models/hepatitis_test.py +2 -2
  334. meta_subject/models/other_arv_regimens_detail.py +1 -1
  335. meta_subject/models/patient_history.py +5 -6
  336. meta_subject/models/physical_exam.py +2 -2
  337. meta_subject/models/pregnancy_update.py +1 -1
  338. meta_subject/models/signals.py +14 -12
  339. meta_subject/models/subject_visit.py +1 -1
  340. meta_subject/models/urine_dipstick_test.py +1 -1
  341. meta_subject/models/urine_pregnancy.py +1 -1
  342. meta_visit_schedule/visit_schedules/__init__.py +2 -0
  343. meta_visit_schedule/visit_schedules/phase_three/__init__.py +2 -0
  344. meta_visit_schedule/visit_schedules/phase_three/schedule.py +2 -2
  345. meta_visit_schedule/visit_schedules/phase_three/schedule_dm_referral.py +1 -2
  346. meta_visit_schedule/visit_schedules/phase_three/schedule_pregnancy.py +1 -2
  347. meta_ae/tests/holidays.csv +0 -15
  348. meta_ae/tests/tests/test_actions.py +0 -126
  349. meta_ae/tests/urls.py +0 -10
  350. meta_analytics/dataframes/glucose_endpoints/utils.py +0 -0
  351. meta_analytics/notebooks/anu.ipynb +0 -95
  352. meta_analytics/notebooks/appointment_planning.ipynb +0 -329
  353. meta_analytics/notebooks/arvs.ipynb +0 -103
  354. meta_analytics/notebooks/cleaning/__init__.py +0 -0
  355. meta_analytics/notebooks/cleaning/consent_v1_ext.ipynb +0 -227
  356. meta_analytics/notebooks/cleaning/offschedule_eos.ipynb +0 -353
  357. meta_analytics/notebooks/dsmc/renal_dysfunction.ipynb +0 -435
  358. meta_analytics/notebooks/endpoints/meta_endpoints_by_date.ipynb +0 -656
  359. meta_analytics/notebooks/followup_examination.ipynb +0 -141
  360. meta_analytics/notebooks/hba1c.ipynb +0 -136
  361. meta_analytics/notebooks/hiv_regimens.ipynb +0 -429
  362. meta_analytics/notebooks/incidence.ipynb +0 -232
  363. meta_analytics/notebooks/liver.ipynb +0 -389
  364. meta_analytics/notebooks/magreth.ipynb +0 -645
  365. meta_analytics/notebooks/monitoring_report.ipynb +0 -1834
  366. meta_analytics/notebooks/pharmacy.ipynb +0 -1061
  367. meta_analytics/notebooks/pharmacy_stock_202410.ipynb +0 -306
  368. meta_analytics/notebooks/qa.ipynb +0 -273
  369. meta_analytics/notebooks/steering.ipynb +0 -61
  370. meta_analytics/notebooks/undiagnosed/meta3_screening_consort_chart.ipynb +0 -1176
  371. meta_analytics/notebooks/undiagnosed/meta3_screening_undiagnosed.ipynb +0 -519
  372. meta_analytics/notebooks/undiagnosed/meta_screening_table2.ipynb +0 -964
  373. meta_analytics/notebooks/undiagnosed/screen_undiagnosed_or.ipynb +0 -296
  374. meta_analytics/notebooks/undiagnosed/screening.ipynb +0 -273
  375. meta_analytics/notebooks/undiagnosed/screening2.ipynb +0 -958
  376. meta_analytics/notebooks/undiagnosed/screening_undiagnosed_20241002.ipynb +0 -958
  377. meta_analytics/notebooks/ven.ipynb +0 -191
  378. meta_analytics/notebooks/vitals.ipynb +0 -263
  379. meta_analytics/tests/__init__.py +0 -0
  380. meta_analytics/tests/test_endpoints_by_date.py +0 -94
  381. meta_consent/tests/__init__.py +0 -0
  382. meta_consent/tests/holidays.csv +0 -15
  383. meta_consent/tests/tests/__init__.py +0 -0
  384. meta_consent/tests/tests/test_form_validators.py +0 -110
  385. meta_consent/tests/tests/test_subject_consent.py +0 -10
  386. meta_consent/tests/urls.py +0 -17
  387. meta_dashboard/tests/__init__.py +0 -0
  388. meta_dashboard/tests/admin.py +0 -22
  389. meta_dashboard/tests/holidays.csv +0 -15
  390. meta_dashboard/tests/tests/__init__.py +0 -0
  391. meta_dashboard/tests/urls.py +0 -55
  392. meta_edc/tests/__init__.py +0 -0
  393. meta_edc/tests/tests/__init__.py +0 -0
  394. meta_edc/tests/tests/test_endpoints.py +0 -555
  395. meta_edc-1.1.8.dist-info/METADATA +0 -767
  396. meta_edc-1.1.8.dist-info/WHEEL +0 -5
  397. meta_edc-1.1.8.dist-info/licenses/AUTHORS.rst +0 -8
  398. meta_edc-1.1.8.dist-info/top_level.txt +0 -20
  399. meta_labs/tests/__init__.py +0 -0
  400. meta_labs/tests/test_labs.py +0 -27
  401. meta_labs/tests/test_reportables.py +0 -70
  402. meta_labs/tests/urls.py +0 -4
  403. meta_lists/tests/__init__.py +0 -0
  404. meta_lists/tests/test_lists.py +0 -8
  405. meta_pharmacy/notebooks/pharmacy.ipynb +0 -41
  406. meta_prn/tests/__init__.py +0 -0
  407. meta_prn/tests/tests/__init__.py +0 -0
  408. meta_prn/tests/tests/test_actions.py +0 -97
  409. meta_prn/tests/tests/test_dm_referral.py +0 -203
  410. meta_prn/tests/tests/test_eos_events.py +0 -134
  411. meta_prn/tests/tests/test_manager_order.py +0 -14
  412. meta_prn/tests/tests/test_pregnancy_notification.py +0 -93
  413. meta_prn/tests/urls.py +0 -10
  414. meta_rando/tests/__init__.py +0 -0
  415. meta_rando/tests/tests/__init__.py +0 -0
  416. meta_rando/tests/tests/test_randomizers.py +0 -57
  417. meta_reports/tests/__init__.py +0 -0
  418. meta_reports/tests/test_reports.py +0 -35
  419. meta_reports/tests/test_sql_gen.py +0 -5
  420. meta_reports/tests/urls.py +0 -4
  421. meta_screening/offline_models.py +0 -3
  422. meta_screening/tests/__init__.py +0 -0
  423. meta_screening/tests/holidays.csv +0 -15
  424. meta_screening/tests/meta_test_case_mixin.py +0 -234
  425. meta_screening/tests/options.py +0 -127
  426. meta_screening/tests/tests/__init__.py +0 -0
  427. meta_screening/tests/tests/test_forms.py +0 -404
  428. meta_screening/tests/tests/test_screening_part_one.py +0 -108
  429. meta_screening/tests/tests/test_screening_part_three.py +0 -433
  430. meta_screening/tests/tests/test_screening_part_two.py +0 -84
  431. meta_sites/tests/__init__.py +0 -0
  432. meta_sites/tests/test_sites.py +0 -12
  433. meta_sites/tests/urls.py +0 -4
  434. meta_stats/__init__.py +0 -0
  435. meta_stats/incidence.py +0 -16
  436. meta_stats/models.py +0 -0
  437. meta_stats/tests/__init__.py +0 -0
  438. meta_stats/tests/tests/__init__.py +0 -0
  439. meta_stats/tests/tests/test_incidence.py +0 -10
  440. meta_subject/tests/__init__.py +0 -0
  441. meta_subject/tests/holidays.csv +0 -15
  442. meta_subject/tests/tests/__init__.py +0 -0
  443. meta_subject/tests/tests/test_egfr.py +0 -234
  444. meta_subject/tests/tests/test_fixes.py +0 -64
  445. meta_subject/tests/tests/test_followup.py +0 -52
  446. meta_subject/tests/tests/test_manager_order.py +0 -11
  447. meta_subject/tests/tests/test_medication_adherence.py +0 -79
  448. meta_subject/tests/tests/test_metadata_rules.py +0 -135
  449. meta_subject/tests/tests/test_mnsi.py +0 -341
  450. meta_subject/tests/tests/test_next_appointment.py +0 -231
  451. meta_subject/tests/tests/test_patient_history_form.py +0 -74
  452. meta_subject/tests/tests/test_physical_exam.py +0 -84
  453. meta_subject/tests/tests/test_sf12.py +0 -161
  454. meta_subject/tests/tests/test_study_medication.py +0 -229
  455. meta_subject/tests/urls.py +0 -24
  456. meta_visit_schedule/tests/__init__.py +0 -0
  457. meta_visit_schedule/tests/tests/__init__.py +0 -0
  458. meta_visit_schedule/tests/tests/test_schedule.py +0 -181
  459. meta_visit_schedule/tests/urls.py +0 -4
  460. tests/__init__.py +0 -0
  461. tests/etc/randomization_list.csv +0 -241
  462. tests/etc/randomization_list_phase_three.csv +0 -241
  463. tests/etc/user-aes-local.key +0 -0
  464. tests/etc/user-aes-restricted.key +0 -1
  465. tests/etc/user-rsa-local-private.pem +0 -27
  466. tests/etc/user-rsa-local-public.pem +0 -9
  467. tests/etc/user-rsa-restricted-private.pem +0 -27
  468. tests/etc/user-rsa-restricted-public.pem +0 -9
  469. tests/etc/user-salt-local.key +0 -0
  470. tests/etc/user-salt-restricted.key +0 -0
  471. tests/holidays.csv +0 -15
  472. tests/test_settings.py +0 -185
  473. {meta_edc-1.1.8.dist-info → meta_edc-1.1.12.dist-info}/licenses/LICENSE +0 -0
  474. /meta_ae/tests/__init__.py → /meta_subject/management/__init__py.py +0 -0
  475. /meta_ae/tests/tests/__init__.py → /meta_subject/management/commands/__init__py.py +0 -0
@@ -1,341 +0,0 @@
1
- from datetime import datetime
2
- from zoneinfo import ZoneInfo
3
-
4
- import time_machine
5
- from dateutil.relativedelta import relativedelta
6
- from django.core.exceptions import ObjectDoesNotExist
7
- from django.test import TestCase, override_settings
8
- from edc_constants.constants import NO, YES
9
- from edc_utils import get_utcnow
10
- from model_bakery import baker
11
-
12
- from meta_screening.tests.meta_test_case_mixin import MetaTestCaseMixin
13
- from meta_subject.models import SubjectVisit
14
- from meta_visit_schedule.constants import (
15
- MONTH1,
16
- MONTH3,
17
- MONTH6,
18
- MONTH9,
19
- MONTH12,
20
- MONTH15,
21
- MONTH18,
22
- MONTH21,
23
- MONTH24,
24
- MONTH27,
25
- MONTH30,
26
- MONTH33,
27
- MONTH36,
28
- MONTH39,
29
- MONTH42,
30
- MONTH45,
31
- MONTH48,
32
- WEEK2,
33
- )
34
-
35
- test_datetime = datetime(2019, 6, 11, 8, 00, tzinfo=ZoneInfo("UTC"))
36
-
37
-
38
- @override_settings(
39
- EDC_PROTOCOL_STUDY_OPEN_DATETIME=test_datetime - relativedelta(years=3),
40
- EDC_PROTOCOL_STUDY_CLOSE_DATETIME=test_datetime + relativedelta(years=3),
41
- )
42
- class TestMnsiRequired(MetaTestCaseMixin, TestCase):
43
- def setUp(self):
44
- super().setUp()
45
- traveller = time_machine.travel(test_datetime)
46
- traveller.start()
47
- self.baseline_datetime = get_utcnow()
48
-
49
- self.subject_screening = self.get_subject_screening(
50
- report_datetime=self.baseline_datetime,
51
- eligibility_datetime=self.baseline_datetime,
52
- )
53
- self.subject_consent = self.get_subject_consent(
54
- self.subject_screening,
55
- consent_datetime=self.baseline_datetime,
56
- )
57
-
58
- self.subject_visit = self.get_subject_visit(
59
- subject_screening=self.subject_screening,
60
- subject_consent=self.subject_consent,
61
- appt_datetime=self.baseline_datetime,
62
- )
63
- traveller.stop()
64
-
65
- def get_visit(self, visit_code: str):
66
- """Returns a scheduled visit with the specified visit code.
67
-
68
- If the visit already exists, it will be returned. If not, it
69
- will be created (along with any interim visits) and returned.
70
- """
71
- subject_identifier = self.subject_consent.subject_identifier
72
- try:
73
- subject_visit = SubjectVisit.objects.get(
74
- subject_identifier=subject_identifier,
75
- visit_code=visit_code,
76
- visit_code_sequence=0,
77
- )
78
- except ObjectDoesNotExist:
79
- subject_visit = (
80
- SubjectVisit.objects.filter(
81
- subject_identifier=subject_identifier,
82
- visit_code_sequence=0,
83
- )
84
- .order_by("visit_code")
85
- .last()
86
- )
87
- while subject_visit.visit_code != visit_code:
88
- subject_visit = self.get_next_subject_visit(subject_visit)
89
-
90
- self.assertEqual(subject_visit.visit_code, visit_code)
91
- self.assertEqual(subject_visit.visit_code_sequence, 0)
92
- return subject_visit
93
-
94
- @staticmethod
95
- def set_mnsi_status(subject_visit, mnsi_performed):
96
- visit_mnsi = baker.make(
97
- "meta_subject.mnsi",
98
- report_datetime=subject_visit.report_datetime,
99
- subject_visit=subject_visit,
100
- mnsi_performed=mnsi_performed,
101
- )
102
- visit_mnsi.save()
103
-
104
- def test_mnsi_not_required_at_baseline(self):
105
- crfs = self.get_crf_metadata(self.subject_visit)
106
- self.assertNotIn("meta_subject.mnsi", [o.model for o in crfs.all()])
107
-
108
- def test_mnsi_not_required_at_2w(self):
109
- crfs = self.get_crf_metadata(self.get_visit(visit_code=WEEK2))
110
- self.assertNotIn("meta_subject.mnsi", [o.model for o in crfs.all()])
111
-
112
- def test_mnsi_required_at_1m(self):
113
- crfs = self.get_crf_metadata(self.get_visit(visit_code=MONTH1))
114
- self.assertIn("meta_subject.mnsi", [o.model for o in crfs.all()])
115
-
116
- def test_mnsi_not_required_at_3m_if_already_performed_at_1m(self):
117
- # MNSI shouldn't be required at any point after it has been performed
118
- month1_visit = self.get_visit(visit_code=MONTH1)
119
- self.set_mnsi_status(subject_visit=month1_visit, mnsi_performed=YES)
120
-
121
- month3_visit = self.get_visit(visit_code=MONTH3)
122
- crfs = self.get_crf_metadata(month3_visit)
123
- self.assertNotIn("meta_subject.mnsi", [o.model for o in crfs.all()])
124
-
125
- def test_mnsi_required_at_3m_if_not_performed_at_1m(self):
126
- month1_visit = self.get_visit(visit_code=MONTH1)
127
- self.set_mnsi_status(subject_visit=month1_visit, mnsi_performed=NO)
128
-
129
- month3_visit = self.get_visit(visit_code=MONTH3)
130
- crfs = self.get_crf_metadata(month3_visit)
131
- self.assertIn("meta_subject.mnsi", [o.model for o in crfs.all()])
132
-
133
- def test_mnsi_not_required_at_6m_if_already_performed_at_1m(self):
134
- # MNSI shouldn't be required at any point after it has been performed
135
- month1_visit = self.get_visit(visit_code=MONTH1)
136
- self.set_mnsi_status(subject_visit=month1_visit, mnsi_performed=YES)
137
-
138
- month3_visit = self.get_visit(visit_code=MONTH3)
139
- crfs = self.get_crf_metadata(month3_visit)
140
- self.assertNotIn("meta_subject.mnsi", [o.model for o in crfs.all()])
141
-
142
- month6_visit = self.get_visit(visit_code=MONTH6)
143
- crfs = self.get_crf_metadata(month6_visit)
144
- self.assertNotIn("meta_subject.mnsi", [o.model for o in crfs.all()])
145
-
146
- def test_mnsi_not_required_at_6m_if_already_performed_at_3m(self):
147
- month1_visit = self.get_visit(visit_code=MONTH1)
148
- self.set_mnsi_status(subject_visit=month1_visit, mnsi_performed=NO)
149
-
150
- # MNSI shouldn't be required at any point after it has been performed
151
- month3_visit = self.get_visit(visit_code=MONTH3)
152
- self.set_mnsi_status(subject_visit=month3_visit, mnsi_performed=YES)
153
-
154
- month6_visit = self.get_visit(visit_code=MONTH6)
155
- crfs = self.get_crf_metadata(month6_visit)
156
- self.assertNotIn("meta_subject.mnsi", [o.model for o in crfs.all()])
157
-
158
- def test_mnsi_required_at_6m_if_not_performed_by_3m(self):
159
- month1_visit = self.get_visit(visit_code=MONTH1)
160
- self.set_mnsi_status(subject_visit=month1_visit, mnsi_performed=NO)
161
-
162
- month3_visit = self.get_visit(visit_code=MONTH3)
163
- self.set_mnsi_status(subject_visit=month3_visit, mnsi_performed=NO)
164
-
165
- month6_visit = self.get_visit(visit_code=MONTH6)
166
- crfs = self.get_crf_metadata(month6_visit)
167
- self.assertIn("meta_subject.mnsi", [o.model for o in crfs.all()])
168
-
169
- def test_mnsi_not_required_at_9m_if_already_performed_at_1m(self):
170
- # MNSI shouldn't be required at any point after it has been performed
171
- month1_visit = self.get_visit(visit_code=MONTH1)
172
- self.set_mnsi_status(subject_visit=month1_visit, mnsi_performed=YES)
173
-
174
- month3_visit = self.get_visit(visit_code=MONTH3)
175
- crfs = self.get_crf_metadata(month3_visit)
176
- self.assertNotIn("meta_subject.mnsi", [o.model for o in crfs.all()])
177
-
178
- month6_visit = self.get_visit(visit_code=MONTH6)
179
- crfs = self.get_crf_metadata(month6_visit)
180
- self.assertNotIn("meta_subject.mnsi", [o.model for o in crfs.all()])
181
-
182
- month9_visit = self.get_visit(visit_code=MONTH9)
183
- crfs = self.get_crf_metadata(month9_visit)
184
- self.assertNotIn("meta_subject.mnsi", [o.model for o in crfs.all()])
185
-
186
- def test_mnsi_not_required_at_9m_if_already_performed_at_3m(self):
187
- month1_visit = self.get_visit(visit_code=MONTH1)
188
- self.set_mnsi_status(subject_visit=month1_visit, mnsi_performed=NO)
189
-
190
- # MNSI shouldn't be required at any point after it has been performed
191
- month3_visit = self.get_visit(visit_code=MONTH3)
192
- self.set_mnsi_status(subject_visit=month3_visit, mnsi_performed=YES)
193
-
194
- month6_visit = self.get_visit(visit_code=MONTH6)
195
- crfs = self.get_crf_metadata(month6_visit)
196
- self.assertNotIn("meta_subject.mnsi", [o.model for o in crfs.all()])
197
-
198
- month9_visit = self.get_visit(visit_code=MONTH9)
199
- crfs = self.get_crf_metadata(month9_visit)
200
- self.assertNotIn("meta_subject.mnsi", [o.model for o in crfs.all()])
201
-
202
- def test_mnsi_not_required_at_9m_if_already_performed_at_6m(self):
203
- month1_visit = self.get_visit(visit_code=MONTH1)
204
- self.set_mnsi_status(subject_visit=month1_visit, mnsi_performed=NO)
205
-
206
- month3_visit = self.get_visit(visit_code=MONTH3)
207
- self.set_mnsi_status(subject_visit=month3_visit, mnsi_performed=NO)
208
-
209
- # MNSI shouldn't be required at any point after it has been performed
210
- month6_visit = self.get_visit(visit_code=MONTH6)
211
- self.set_mnsi_status(subject_visit=month6_visit, mnsi_performed=YES)
212
-
213
- month9_visit = self.get_visit(visit_code=MONTH9)
214
- crfs = self.get_crf_metadata(month9_visit)
215
- self.assertNotIn("meta_subject.mnsi", [o.model for o in crfs.all()])
216
-
217
- def test_mnsi_not_required_between_9m_and_33m_when_performed_in_first_6m(self):
218
- month1_visit = self.get_visit(visit_code=MONTH1)
219
- self.set_mnsi_status(subject_visit=month1_visit, mnsi_performed=NO)
220
-
221
- month3_visit = self.get_visit(visit_code=MONTH3)
222
- self.set_mnsi_status(subject_visit=month3_visit, mnsi_performed=YES)
223
-
224
- for visit_code in [
225
- MONTH9,
226
- MONTH12,
227
- MONTH15,
228
- MONTH18,
229
- MONTH21,
230
- MONTH24,
231
- MONTH27,
232
- MONTH30,
233
- MONTH33,
234
- ]:
235
- with self.subTest(visit_code=visit_code):
236
- subject_visit = self.get_visit(visit_code=visit_code)
237
- self.assertEqual(subject_visit.visit_code, visit_code)
238
- self.assertEqual(subject_visit.visit_code_sequence, 0)
239
- crfs = self.get_crf_metadata(subject_visit)
240
- self.assertNotIn("meta_subject.mnsi", [o.model for o in crfs.all()])
241
-
242
- def test_mnsi_not_required_between_9m_and_33m_even_if_not_performed_first_6m(self):
243
- month1_visit = self.get_visit(visit_code=MONTH1)
244
- self.set_mnsi_status(subject_visit=month1_visit, mnsi_performed=NO)
245
-
246
- month3_visit = self.get_visit(visit_code=MONTH3)
247
- self.set_mnsi_status(subject_visit=month3_visit, mnsi_performed=NO)
248
-
249
- month6_visit = self.get_visit(visit_code=MONTH6)
250
- self.set_mnsi_status(subject_visit=month6_visit, mnsi_performed=NO)
251
-
252
- for visit_code in [
253
- MONTH9,
254
- MONTH12,
255
- MONTH15,
256
- MONTH18,
257
- MONTH21,
258
- MONTH24,
259
- MONTH27,
260
- MONTH30,
261
- MONTH33,
262
- ]:
263
- with self.subTest(visit_code=visit_code):
264
- subject_visit = self.get_visit(visit_code=visit_code)
265
- self.assertEqual(subject_visit.visit_code, visit_code)
266
- self.assertEqual(subject_visit.visit_code_sequence, 0)
267
- crfs = self.get_crf_metadata(subject_visit)
268
- self.assertNotIn("meta_subject.mnsi", [o.model for o in crfs.all()])
269
-
270
- def test_mnsi_required_between_36m_and_45m(self):
271
- traveller = time_machine.travel(datetime(2024, 12, 17, tzinfo=ZoneInfo("UTC")))
272
- traveller.start()
273
- self.get_subject_consent_extended(self.subject_consent, consent_datetime=get_utcnow())
274
- traveller.stop()
275
-
276
- month1_visit = self.get_visit(visit_code=MONTH1)
277
- traveller = time_machine.travel(month1_visit.report_datetime)
278
- traveller.start()
279
- self.set_mnsi_status(subject_visit=month1_visit, mnsi_performed=YES)
280
-
281
- for visit_code in [MONTH36, MONTH39, MONTH42, MONTH45]:
282
- with self.subTest(visit_code=visit_code):
283
- subject_visit = self.get_visit(visit_code=visit_code)
284
- crfs = self.get_crf_metadata(subject_visit)
285
- self.assertIn("meta_subject.mnsi", [o.model for o in crfs.all()])
286
- self.set_mnsi_status(subject_visit=subject_visit, mnsi_performed=NO)
287
- traveller.stop()
288
-
289
- def test_mnsi_only_required_once_between_36m_and_45m(self):
290
- traveller = time_machine.travel(datetime(2024, 12, 17, tzinfo=ZoneInfo("UTC")))
291
- traveller.start()
292
- self.get_subject_consent_extended(self.subject_consent, consent_datetime=get_utcnow())
293
- month1_visit = self.get_visit(visit_code=MONTH1)
294
- self.set_mnsi_status(subject_visit=month1_visit, mnsi_performed=YES)
295
-
296
- month36_visit = self.get_visit(visit_code=MONTH36)
297
- crfs = self.get_crf_metadata(month36_visit)
298
- self.assertIn("meta_subject.mnsi", [o.model for o in crfs.all()])
299
- self.set_mnsi_status(subject_visit=month36_visit, mnsi_performed=NO)
300
-
301
- month39_visit = self.get_next_subject_visit(month36_visit)
302
- crfs = self.get_crf_metadata(month39_visit)
303
- self.assertIn("meta_subject.mnsi", [o.model for o in crfs.all()])
304
- self.set_mnsi_status(subject_visit=month39_visit, mnsi_performed=NO)
305
-
306
- month42_visit = self.get_next_subject_visit(month39_visit)
307
- crfs = self.get_crf_metadata(month42_visit)
308
- self.assertIn("meta_subject.mnsi", [o.model for o in crfs.all()])
309
- self.set_mnsi_status(subject_visit=month42_visit, mnsi_performed=YES)
310
-
311
- month45_visit = self.get_next_subject_visit(month42_visit)
312
- crfs = self.get_crf_metadata(month45_visit)
313
- self.assertNotIn("meta_subject.mnsi", [o.model for o in crfs.all()])
314
- traveller.stop()
315
-
316
- def test_mnsi_required_at_48m(self):
317
- traveller = time_machine.travel(datetime(2024, 12, 16, tzinfo=ZoneInfo("UTC")))
318
- traveller.start()
319
- self.get_subject_consent_extended(self.subject_consent, consent_datetime=get_utcnow())
320
- month1_visit = self.get_visit(visit_code=MONTH1)
321
- crfs = self.get_crf_metadata(month1_visit)
322
- self.assertIn("meta_subject.mnsi", [o.model for o in crfs.all()])
323
- self.set_mnsi_status(subject_visit=month1_visit, mnsi_performed=YES)
324
-
325
- month3_visit = self.get_next_subject_visit(month1_visit)
326
- crfs = self.get_crf_metadata(month3_visit)
327
- self.assertNotIn("meta_subject.mnsi", [o.model for o in crfs.all()])
328
-
329
- month36_visit = self.get_visit(visit_code=MONTH36)
330
- crfs = self.get_crf_metadata(month36_visit)
331
- self.assertIn("meta_subject.mnsi", [o.model for o in crfs.all()])
332
- self.set_mnsi_status(subject_visit=month36_visit, mnsi_performed=YES)
333
-
334
- month39_visit = self.get_next_subject_visit(month36_visit)
335
- crfs = self.get_crf_metadata(month39_visit)
336
- self.assertNotIn("meta_subject.mnsi", [o.model for o in crfs.all()])
337
-
338
- month48_visit = self.get_visit(visit_code=MONTH48)
339
- crfs = self.get_crf_metadata(month48_visit)
340
- self.assertIn("meta_subject.mnsi", [o.model for o in crfs.all()])
341
- traveller.stop()
@@ -1,231 +0,0 @@
1
- from datetime import datetime
2
- from zoneinfo import ZoneInfo
3
-
4
- import time_machine
5
- from dateutil.relativedelta import relativedelta
6
- from django.core.exceptions import ValidationError
7
- from django.test import TestCase, tag
8
- from edc_appointment.exceptions import AppointmentWindowError
9
- from edc_constants.constants import CLINIC
10
- from edc_facility.models import HealthFacilityTypes
11
- from edc_facility.utils import get_health_facility_model, get_health_facility_model_cls
12
- from edc_metadata.metadata_handler import MetadataHandlerError
13
- from edc_sites.utils import get_site_model_cls
14
- from edc_visit_schedule.models import VisitSchedule
15
-
16
- from meta_screening.tests.meta_test_case_mixin import MetaTestCaseMixin
17
- from meta_screening.tests.options import now
18
- from meta_subject.models import NextAppointment
19
-
20
-
21
- @time_machine.travel(datetime(2019, 6, 11, 8, 00, tzinfo=ZoneInfo("UTC")))
22
- class TestNextAppointment(MetaTestCaseMixin, TestCase):
23
-
24
- def setUp(self):
25
- super().setUp()
26
- self.update_health_facility_model()
27
- self.subject_visit = self.get_subject_visit(appt_datetime=now)
28
-
29
- def update_health_facility_model(self):
30
- from edc_sites.site import sites as site_sites
31
-
32
- clinic = HealthFacilityTypes.objects.get(name=CLINIC)
33
- for site_obj in get_site_model_cls().objects.all():
34
- single_site = site_sites.get(site_obj.id)
35
- get_health_facility_model_cls().objects.create(
36
- name=single_site.name,
37
- title=single_site.title,
38
- health_facility_type=clinic,
39
- mon=True,
40
- tue=True,
41
- wed=True,
42
- thu=True,
43
- fri=True,
44
- sat=False,
45
- sun=False,
46
- site_id=site_obj.id,
47
- )
48
-
49
- @tag("6")
50
- def test_in_visit_crfs(self):
51
- dt = self.subject_visit.report_datetime.date() + relativedelta(days=10)
52
- for i in range(1, 7):
53
- dt = dt + relativedelta(days=1)
54
- if dt.weekday() < 6:
55
- break
56
-
57
- try:
58
- NextAppointment.objects.create(
59
- subject_visit=self.subject_visit,
60
- report_datetime=self.subject_visit.report_datetime,
61
- appt_date=dt,
62
- health_facility=get_health_facility_model_cls().objects.all()[0],
63
- )
64
- except MetadataHandlerError as e:
65
- self.fail(f"Unexpected MetadataHandlerError. Got {e}")
66
-
67
- @tag("6")
68
- def test_validates_clinic_day(self):
69
- dt = self.subject_visit.report_datetime.date() + relativedelta(days=10)
70
- for i in range(1, 7):
71
- dt = dt + relativedelta(days=1)
72
- if dt.weekday() > 5:
73
- break
74
- with self.assertRaises(ValidationError) as cm:
75
- NextAppointment.objects.create(
76
- subject_visit=self.subject_visit,
77
- report_datetime=self.subject_visit.report_datetime,
78
- appt_date=dt,
79
- health_facility=get_health_facility_model_cls().objects.all()[0],
80
- )
81
- self.assertIn("Expected Mon-Fri", str(cm.exception))
82
-
83
- @tag("6")
84
- def test_appt_date_on_report_date_raises(self):
85
- with self.assertRaises(ValidationError) as cm:
86
- NextAppointment.objects.create(
87
- subject_visit=self.subject_visit,
88
- report_datetime=self.subject_visit.report_datetime,
89
- appt_date=self.subject_visit.report_datetime.date(),
90
- health_facility=get_health_facility_model_cls().objects.all()[0],
91
- )
92
- self.assertIn(
93
- "Cannot be equal to the report datetime",
94
- str(cm.exception),
95
- )
96
-
97
- # @tag("6")
98
- # def test_next_appt_date_required(self):
99
- # next_appt = self.subject_visit.appointment.next
100
- # with self.assertRaises(NextAppointmentModelError) as cm:
101
- # NextAppointment.objects.create(
102
- # subject_visit=self.subject_visit,
103
- # report_datetime=self.subject_visit.report_datetime,
104
- # health_facility=get_health_facility_model_cls().objects.all()[0],
105
- # visitschedule=VisitSchedule.objects.get(
106
- # visit_schedule_name=self.subject_visit.visit_schedule.name,
107
- # timepoint=next_appt.timepoint,
108
- # ),
109
- # )
110
- # self.assertIn(
111
- # "Appointment date or datetime is required",
112
- # str(cm.exception),
113
- # )
114
-
115
- @tag("6")
116
- def test_nextappt_appt_date_updates_nextappt_appt_datetime(self):
117
- next_appt = self.subject_visit.appointment.next
118
- original_next_appt_datetime = self.subject_visit.appointment.next.appt_datetime
119
- obj = NextAppointment.objects.create(
120
- appt_date=original_next_appt_datetime.date(),
121
- subject_visit=self.subject_visit,
122
- report_datetime=self.subject_visit.report_datetime,
123
- health_facility=get_health_facility_model_cls().objects.all()[0],
124
- visitschedule=VisitSchedule.objects.get(
125
- visit_schedule_name=self.subject_visit.visit_schedule.name,
126
- timepoint=next_appt.timepoint,
127
- ),
128
- )
129
- self.assertIsNotNone(obj.appt_datetime)
130
-
131
- # @tag("6")
132
- # def test_nextappt_appt_datetime_updates_nextappt_appt_date(self):
133
- # next_appt = self.subject_visit.appointment.next
134
- # original_next_appt_datetime = self.subject_visit.appointment.next.appt_datetime
135
- # obj = NextAppointment.objects.create(
136
- # appt_datetime=original_next_appt_datetime,
137
- # subject_visit=self.subject_visit,
138
- # report_datetime=self.subject_visit.report_datetime,
139
- # health_facility=get_health_facility_model_cls().objects.all()[0],
140
- # visitschedule=VisitSchedule.objects.get(
141
- # visit_schedule_name=self.subject_visit.visit_schedule.name,
142
- # timepoint=next_appt.timepoint,
143
- # ),
144
- # )
145
- # self.assertIsNotNone(obj.appt_date)
146
-
147
- @tag("6")
148
- def test_next_appt_date_same_as_original_next_appt(self):
149
- get_health_facility_model()
150
- next_appt = self.subject_visit.appointment.next
151
- obj = NextAppointment.objects.create(
152
- subject_visit=self.subject_visit,
153
- report_datetime=self.subject_visit.report_datetime,
154
- appt_date=next_appt.appt_datetime.date(),
155
- health_facility=get_health_facility_model_cls().objects.all()[0],
156
- visitschedule=VisitSchedule.objects.get(
157
- visit_schedule_name=self.subject_visit.visit_schedule.name,
158
- timepoint=next_appt.timepoint,
159
- ),
160
- )
161
- next_appt.refresh_from_db()
162
- self.assertEqual(next_appt.appt_datetime, obj.appt_datetime)
163
-
164
- @tag("6")
165
- def test_updates_next_appointment_datetime(self):
166
- next_appt = self.subject_visit.appointment.next
167
- original_next_appt_datetime = self.subject_visit.appointment.next.appt_datetime
168
- obj = NextAppointment.objects.create(
169
- subject_visit=self.subject_visit,
170
- report_datetime=self.subject_visit.report_datetime,
171
- appt_date=original_next_appt_datetime.date() + relativedelta(days=1),
172
- health_facility=get_health_facility_model_cls().objects.all()[0],
173
- visitschedule=VisitSchedule.objects.get(
174
- visit_schedule_name=self.subject_visit.visit_schedule.name,
175
- timepoint=next_appt.timepoint,
176
- ),
177
- )
178
- next_appt.refresh_from_db()
179
- self.assertEqual(next_appt.appt_datetime, obj.appt_datetime)
180
-
181
- @tag("6")
182
- def test_raises_if_next_appointment_datetime_is_before_current(self):
183
- next_appt = self.subject_visit.appointment.next
184
- current_appt_datetime = self.subject_visit.appointment.appt_datetime
185
- self.assertRaises(
186
- ValidationError,
187
- NextAppointment.objects.create,
188
- subject_visit=self.subject_visit,
189
- report_datetime=self.subject_visit.report_datetime,
190
- appt_date=current_appt_datetime.date(),
191
- health_facility=get_health_facility_model_cls().objects.all()[0],
192
- visitschedule=VisitSchedule.objects.get(
193
- visit_schedule_name=self.subject_visit.visit_schedule.name,
194
- timepoint=next_appt.timepoint,
195
- ),
196
- )
197
-
198
- @tag("6")
199
- def test_raises_on_appt_date_outside_of_window_for_selected_visit_code(self):
200
- next_appt = self.subject_visit.appointment.next
201
- bad_next_date = self.subject_visit.report_datetime.date() + relativedelta(days=1)
202
- self.assertRaises(
203
- AppointmentWindowError,
204
- NextAppointment.objects.create,
205
- subject_visit=self.subject_visit,
206
- report_datetime=self.subject_visit.report_datetime,
207
- appt_date=bad_next_date,
208
- health_facility=get_health_facility_model_cls().objects.all()[0],
209
- visitschedule=VisitSchedule.objects.get(
210
- visit_schedule_name=self.subject_visit.visit_schedule.name,
211
- timepoint=next_appt.timepoint,
212
- ),
213
- )
214
-
215
- @tag("6")
216
- def test_next_is_interim_or_unscheduled(self):
217
- dt = self.subject_visit.report_datetime.date() + relativedelta(days=10)
218
- for i in range(1, 7):
219
- dt = dt + relativedelta(days=1)
220
- if dt.weekday() < 6:
221
- break
222
- NextAppointment.objects.create(
223
- subject_visit=self.subject_visit,
224
- report_datetime=self.subject_visit.report_datetime,
225
- appt_date=dt,
226
- health_facility=get_health_facility_model_cls().objects.all()[0],
227
- visitschedule=VisitSchedule.objects.get(
228
- visit_schedule_name=self.subject_visit.visit_schedule.name,
229
- timepoint=self.subject_visit.appointment.timepoint,
230
- ),
231
- )
@@ -1,74 +0,0 @@
1
- from django.conf import settings
2
- from django.contrib.sites.models import Site
3
- from django.test import TestCase
4
- from edc_constants.constants import COMPLETE, NO, NONE, NOT_APPLICABLE, YES
5
- from edc_list_data import PreloadData
6
-
7
- from meta_lists.models import (
8
- ArvRegimens,
9
- BaselineSymptoms,
10
- DiabetesSymptoms,
11
- OiProphylaxis,
12
- )
13
- from meta_screening.tests.meta_test_case_mixin import MetaTestCaseMixin
14
- from meta_screening.tests.options import now
15
- from meta_subject.forms import PatientHistoryForm
16
-
17
-
18
- class BaseTestPatientHistory(MetaTestCaseMixin, TestCase):
19
- def get_options(self):
20
- self.subject_visit = self.get_subject_visit(appt_datetime=now)
21
- symptoms = BaselineSymptoms.objects.filter(name=NONE)
22
- arv_regimen = ArvRegimens.objects.filter(name="TDF_3TC_ATV_r")
23
- oi_prophylaxis = OiProphylaxis.objects.filter(name__in=["fluconazole", "isoniazid"])
24
- dm_symptoms = DiabetesSymptoms.objects.all()
25
- return {
26
- "current_arv_regimen": arv_regimen[0].id,
27
- "current_smoker": YES,
28
- "dia_blood_pressure": 80,
29
- "dm_in_family": NO,
30
- "dm_symptoms": dm_symptoms,
31
- "dyslipidaemia_diagnosis": NO,
32
- "on_dyslipidaemia_treatment": NOT_APPLICABLE,
33
- "dyslipidaemia_rx": NOT_APPLICABLE,
34
- "family_diabetics": NO,
35
- "former_smoker": NOT_APPLICABLE,
36
- "has_abdominal_tenderness": NO,
37
- "has_enlarged_liver": NO,
38
- "has_previous_arv_regimen": NO,
39
- "heart_rate": 65,
40
- "htn_diagnosis": NO,
41
- "htn_treatment": None,
42
- "is_heartbeat_regular": YES,
43
- "jaundice": YES,
44
- "oi_prophylaxis": oi_prophylaxis,
45
- "on_htn_treatment": NO,
46
- "on_oi_prophylaxis": YES,
47
- "other_dm_symptoms": "erik",
48
- "past_year_symptoms": None,
49
- "peripheral_oedema": YES,
50
- "previous_arv_regimen": [],
51
- "report_datetime": self.subject_visit.report_datetime,
52
- "respiratory_rate": 12,
53
- "subject_visit": self.subject_visit.pk,
54
- "symptoms": symptoms,
55
- "sys_blood_pressure": 120,
56
- "taking_statins": YES,
57
- "temperature": 37,
58
- "waist_circumference": 61,
59
- "weight": 65,
60
- "crf_status": COMPLETE,
61
- "vl_undetectable": YES,
62
- "site": Site.objects.get(id=settings.SITE_ID),
63
- }
64
-
65
-
66
- class TestPatientHistoryPhaseThree(BaseTestPatientHistory):
67
- def test_ok_phase_three(self):
68
- from meta_lists.list_data import list_data
69
-
70
- PreloadData(list_data=list_data)
71
- data = {k: v for k, v in self.get_options().items()}
72
- form = PatientHistoryForm(data=data)
73
- form.is_valid()
74
- self.assertEqual(form._errors, {})